summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/api/web.rs43
-rw-r--r--src/static/scripts/admin.js85
-rw-r--r--src/static/scripts/admin_diagnostics.js4
-rw-r--r--src/static/scripts/admin_users.js14
-rw-r--r--src/static/scripts/bootstrap-native.js5991
-rw-r--r--src/static/scripts/bootstrap.bundle.js6313
-rw-r--r--src/static/scripts/bootstrap.css2377
-rw-r--r--src/static/scripts/datatables.css47
-rw-r--r--src/static/scripts/datatables.js93
-rw-r--r--src/static/scripts/jquery-3.7.0.slim.js (renamed from src/static/scripts/jquery-3.6.4.slim.js)1837
-rw-r--r--src/static/templates/admin/base.hbs58
-rw-r--r--src/static/templates/admin/diagnostics.hbs6
-rw-r--r--src/static/templates/admin/login.hbs10
-rw-r--r--src/static/templates/admin/organizations.hbs4
-rw-r--r--src/static/templates/admin/settings.hbs6
-rw-r--r--src/static/templates/admin/users.hbs6
16 files changed, 9160 insertions, 7734 deletions
diff --git a/src/api/web.rs b/src/api/web.rs
index 5cdcb15e..a75b9e4e 100644
--- a/src/api/web.rs
+++ b/src/api/web.rs
@@ -14,11 +14,17 @@ use crate::{
pub fn routes() -> Vec<Route> {
// If addding more routes here, consider also adding them to
// crate::utils::LOGGED_ROUTES to make sure they appear in the log
+ let mut routes = routes![attachments, alive, alive_head, static_files];
if CONFIG.web_vault_enabled() {
- routes![web_index, web_index_head, app_id, web_files, attachments, alive, alive_head, static_files]
- } else {
- routes![attachments, alive, alive_head, static_files]
+ routes.append(&mut routes![web_index, web_index_head, app_id, web_files]);
+ }
+
+ #[cfg(debug_assertions)]
+ if CONFIG.reload_templates() {
+ routes.append(&mut routes![_static_files_dev]);
}
+
+ routes
}
pub fn catchers() -> Vec<Catcher> {
@@ -116,7 +122,30 @@ fn alive_head(_conn: DbConn) -> EmptyResult {
Ok(())
}
-#[get("/vw_static/<filename>")]
+// This endpoint/function is used during development and development only.
+// It allows to easily develop the admin interface by always loading the files from disk instead from a slice of bytes
+// This will only be active during a debug build and only when `RELOAD_TEMPLATES` is set to `true`
+// NOTE: Do not forget to add any new files added to the `static_files` function below!
+#[cfg(debug_assertions)]
+#[get("/vw_static/<filename>", rank = 1)]
+pub async fn _static_files_dev(filename: PathBuf) -> Option<NamedFile> {
+ warn!("LOADING STATIC FILES FROM DISK");
+ let file = filename.to_str().unwrap_or_default();
+ let ext = filename.extension().unwrap_or_default();
+
+ let path = if ext == "png" || ext == "svg" {
+ tokio::fs::canonicalize(Path::new(file!()).parent().unwrap().join("../static/images/").join(file)).await
+ } else {
+ tokio::fs::canonicalize(Path::new(file!()).parent().unwrap().join("../static/scripts/").join(file)).await
+ };
+
+ if let Ok(path) = path {
+ return NamedFile::open(path).await.ok();
+ };
+ None
+}
+
+#[get("/vw_static/<filename>", rank = 2)]
pub fn static_files(filename: &str) -> Result<(ContentType, &'static [u8]), Error> {
match filename {
"404.png" => Ok((ContentType::PNG, include_bytes!("../static/images/404.png"))),
@@ -138,12 +167,12 @@ pub fn static_files(filename: &str) -> Result<(ContentType, &'static [u8]), Erro
Ok((ContentType::JavaScript, include_bytes!("../static/scripts/admin_diagnostics.js")))
}
"bootstrap.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/bootstrap.css"))),
- "bootstrap-native.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native.js"))),
+ "bootstrap.bundle.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap.bundle.js"))),
"jdenticon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jdenticon.js"))),
"datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
"datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
- "jquery-3.6.4.slim.js" => {
- Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.4.slim.js")))
+ "jquery-3.7.0.slim.js" => {
+ Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.7.0.slim.js")))
}
_ => err!(format!("Static file not found: {filename}")),
}
diff --git a/src/static/scripts/admin.js b/src/static/scripts/admin.js
index a9c19739..b35f3fb1 100644
--- a/src/static/scripts/admin.js
+++ b/src/static/scripts/admin.js
@@ -37,36 +37,107 @@ function _post(url, successMsg, errMsg, body, reload_page = true) {
mode: "same-origin",
credentials: "same-origin",
headers: { "Content-Type": "application/json" }
- }).then( resp => {
+ }).then(resp => {
if (resp.ok) {
msg(successMsg, reload_page);
// Abuse the catch handler by setting error to false and continue
- return Promise.reject({error: false});
+ return Promise.reject({ error: false });
}
respStatus = resp.status;
respStatusText = resp.statusText;
return resp.text();
- }).then( respText => {
+ }).then(respText => {
try {
const respJson = JSON.parse(respText);
if (respJson.ErrorModel && respJson.ErrorModel.Message) {
return respJson.ErrorModel.Message;
} else {
- return Promise.reject({body:`${respStatus} - ${respStatusText}\n\nUnknown error`, error: true});
+ return Promise.reject({ body: `${respStatus} - ${respStatusText}\n\nUnknown error`, error: true });
}
} catch (e) {
- return Promise.reject({body:`${respStatus} - ${respStatusText}\n\n[Catch] ${e}`, error: true});
+ return Promise.reject({ body: `${respStatus} - ${respStatusText}\n\n[Catch] ${e}`, error: true });
}
- }).then( apiMsg => {
+ }).then(apiMsg => {
msg(`${errMsg}\n${apiMsg}`, reload_page);
- }).catch( e => {
+ }).catch(e => {
if (e.error === false) { return true; }
else { msg(`${errMsg}\n${e.body}`, reload_page); }
});
}
+// Bootstrap Theme Selector
+const getStoredTheme = () => localStorage.getItem("theme");
+const setStoredTheme = theme => localStorage.setItem("theme", theme);
+
+const getPreferredTheme = () => {
+ const storedTheme = getStoredTheme();
+ if (storedTheme) {
+ return storedTheme;
+ }
+
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+};
+
+const setTheme = theme => {
+ if (theme === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches) {
+ document.documentElement.setAttribute("data-bs-theme", "dark");
+ } else {
+ document.documentElement.setAttribute("data-bs-theme", theme);
+ }
+};
+
+setTheme(getPreferredTheme());
+
+const showActiveTheme = (theme, focus = false) => {
+ const themeSwitcher = document.querySelector("#bd-theme");
+
+ if (!themeSwitcher) {
+ return;
+ }
+
+ const themeSwitcherText = document.querySelector("#bd-theme-text");
+ const activeThemeIcon = document.querySelector(".theme-icon-active use");
+ const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`);
+ const svgOfActiveBtn = btnToActive.querySelector("span use").innerText;
+
+ document.querySelectorAll("[data-bs-theme-value]").forEach(element => {
+ element.classList.remove("active");
+ element.setAttribute("aria-pressed", "false");
+ });
+
+ btnToActive.classList.add("active");
+ btnToActive.setAttribute("aria-pressed", "true");
+ activeThemeIcon.innerText = svgOfActiveBtn;
+ const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`;
+ themeSwitcher.setAttribute("aria-label", themeSwitcherLabel);
+
+ if (focus) {
+ themeSwitcher.focus();
+ }
+};
+
+window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
+ const storedTheme = getStoredTheme();
+ if (storedTheme !== "light" && storedTheme !== "dark") {
+ setTheme(getPreferredTheme());
+ }
+});
+
+
// onLoad events
document.addEventListener("DOMContentLoaded", (/*event*/) => {
+ showActiveTheme(getPreferredTheme());
+
+ document.querySelectorAll("[data-bs-theme-value]")
+ .forEach(toggle => {
+ toggle.addEventListener("click", () => {
+ const theme = toggle.getAttribute("data-bs-theme-value");
+ setStoredTheme(theme);
+ setTheme(theme);
+ showActiveTheme(theme, true);
+ });
+ });
+
// get current URL path and assign "active" class to the correct nav-item
const pathname = window.location.pathname;
if (pathname === "") return;
diff --git a/src/static/scripts/admin_diagnostics.js b/src/static/scripts/admin_diagnostics.js
index 5fbed2da..0b1d0622 100644
--- a/src/static/scripts/admin_diagnostics.js
+++ b/src/static/scripts/admin_diagnostics.js
@@ -1,6 +1,6 @@
"use strict";
/* eslint-env es2017, browser */
-/* global BASE_URL:readable, BSN:readable */
+/* global BASE_URL:readable, bootstrap:readable */
var dnsCheck = false;
var timeCheck = false;
@@ -135,7 +135,7 @@ function copyToClipboard(event) {
document.execCommand("copy");
tmpCopyEl.remove();
- new BSN.Toast("#toastClipboardCopy").show();
+ new bootstrap.Toast("#toastClipboardCopy").show();
}
function checkTimeDrift(utcTimeA, utcTimeB, statusPrefix) {
diff --git a/src/static/scripts/admin_users.js b/src/static/scripts/admin_users.js
index a931a4a9..8b569296 100644
--- a/src/static/scripts/admin_users.js
+++ b/src/static/scripts/admin_users.js
@@ -141,19 +141,20 @@ function resendUserInvite (event) {
const ORG_TYPES = {
"0": {
"name": "Owner",
- "color": "orange"
+ "bg": "orange",
+ "font": "black"
},
"1": {
"name": "Admin",
- "color": "blueviolet"
+ "bg": "blueviolet"
},
"2": {
"name": "User",
- "color": "blue"
+ "bg": "blue"
},
"3": {
"name": "Manager",
- "color": "green"
+ "bg": "green"
},
};
@@ -227,7 +228,10 @@ function initUserTable() {
// Color all the org buttons per type
document.querySelectorAll("button[data-vw-org-type]").forEach(function(e) {
const orgType = ORG_TYPES[e.dataset.vwOrgType];
- e.style.backgroundColor = orgType.color;
+ e.style.backgroundColor = orgType.bg;
+ if (orgType.font !== undefined) {
+ e.style.color = orgType.font;
+ }
e.title = orgType.name;
});
diff --git a/src/static/scripts/bootstrap-native.js b/src/static/scripts/bootstrap-native.js
deleted file mode 100644
index bf26cef8..00000000
--- a/src/static/scripts/bootstrap-native.js
+++ /dev/null
@@ -1,5991 +0,0 @@
-/*!
- * Native JavaScript for Bootstrap v4.2.0 (https://thednp.github.io/bootstrap.native/)
- * Copyright 2015-2022 © dnp_theme
- * Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
- */
-(function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BSN = factory());
-})(this, (function () { 'use strict';
-
- /** @type {Record<string, any>} */
- const EventRegistry = {};
-
- /**
- * The global event listener.
- *
- * @type {EventListener}
- * @this {EventTarget}
- */
- function globalListener(e) {
- const that = this;
- const { type } = e;
-
- [...EventRegistry[type]].forEach((elementsMap) => {
- const [element, listenersMap] = elementsMap;
- /* istanbul ignore else */
- if (element === that) {
- [...listenersMap].forEach((listenerMap) => {
- const [listener, options] = listenerMap;
- listener.apply(element, [e]);
-
- if (options && options.once) {
- removeListener(element, type, listener, options);
- }
- });
- }
- });
- }
-
- /**
- * Register a new listener with its options and attach the `globalListener`
- * to the target if this is the first listener.
- *
- * @type {Listener.ListenerAction<EventTarget>}
- */
- const addListener = (element, eventType, listener, options) => {
- // get element listeners first
- if (!EventRegistry[eventType]) {
- EventRegistry[eventType] = new Map();
- }
- const oneEventMap = EventRegistry[eventType];
-
- if (!oneEventMap.has(element)) {
- oneEventMap.set(element, new Map());
- }
- const oneElementMap = oneEventMap.get(element);
-
- // get listeners size
- const { size } = oneElementMap;
-
- // register listener with its options
- oneElementMap.set(listener, options);
-
- // add listener last
- if (!size) {
- element.addEventListener(eventType, globalListener, options);
- }
- };
-
- /**
- * Remove a listener from registry and detach the `globalListener`
- * if no listeners are found in the registry.
- *
- * @type {Listener.ListenerAction<EventTarget>}
- */
- const removeListener = (element, eventType, listener, options) => {
- // get listener first
- const oneEventMap = EventRegistry[eventType];
- const oneElementMap = oneEventMap && oneEventMap.get(element);
- const savedOptions = oneElementMap && oneElementMap.get(listener);
-
- // also recover initial options
- const { options: eventOptions } = savedOptions !== undefined
- ? savedOptions
- : { options };
-
- // unsubscribe second, remove from registry
- if (oneElementMap && oneElementMap.has(listener)) oneElementMap.delete(listener);
- if (oneEventMap && (!oneElementMap || !oneElementMap.size)) oneEventMap.delete(element);
- if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
-
- // remove listener last
- /* istanbul ignore else */
- if (!oneElementMap || !oneElementMap.size) {
- element.removeEventListener(eventType, globalListener, eventOptions);
- }
- };
-
- /**
- * Advanced event listener based on subscribe / publish pattern.
- * @see https://www.patterns.dev/posts/classic-design-patterns/#observerpatternjavascript
- * @see https://gist.github.com/shystruk/d16c0ee7ac7d194da9644e5d740c8338#file-subpub-js
- * @see https://hackernoon.com/do-you-still-register-window-event-listeners-in-each-component-react-in-example-31a4b1f6f1c8
- */
- const Listener = {
- on: addListener,
- off: removeListener,
- globalListener,
- registry: EventRegistry,
- };
-
- /**
- * A global namespace for `click` event.
- * @type {string}
- */
- const mouseclickEvent = 'click';
-
- /**
- * A global namespace for 'transitionend' string.
- * @type {string}
- */
- const transitionEndEvent = 'transitionend';
-
- /**
- * A global namespace for 'transitionDelay' string.
- * @type {string}
- */
- const transitionDelay = 'transitionDelay';
-
- /**
- * A global namespace for `transitionProperty` string for modern browsers.
- *
- * @type {string}
- */
- const transitionProperty = 'transitionProperty';
-
- /**
- * Shortcut for `window.getComputedStyle(element).propertyName`
- * static method.
- *
- * * If `element` parameter is not an `HTMLElement`, `getComputedStyle`
- * throws a `ReferenceError`.
- *
- * @param {HTMLElement} element target
- * @param {string} property the css property
- * @return {string} the css property value
- */
- function getElementStyle(element, property) {
- const computedStyle = getComputedStyle(element);
-
- // must use camelcase strings,
- // or non-camelcase strings with `getPropertyValue`
- return property.includes('--')
- ? computedStyle.getPropertyValue(property)
- : computedStyle[property];
- }
-
- /**
- * Utility to get the computed `transitionDelay`
- * from Element in miliseconds.
- *
- * @param {HTMLElement} element target
- * @return {number} the value in miliseconds
- */
- function getElementTransitionDelay(element) {
- const propertyValue = getElementStyle(element, transitionProperty);
- const delayValue = getElementStyle(element, transitionDelay);
- const delayScale = delayValue.includes('ms') ? /* istanbul ignore next */1 : 1000;
- const duration = propertyValue && propertyValue !== 'none'
- ? parseFloat(delayValue) * delayScale : 0;
-
- return !Number.isNaN(duration) ? duration : /* istanbul ignore next */0;
- }
-
- /**
- * A global namespace for 'transitionDuration' string.
- * @type {string}
- */
- const transitionDuration = 'transitionDuration';
-
- /**
- * Utility to get the computed `transitionDuration`
- * from Element in miliseconds.
- *
- * @param {HTMLElement} element target
- * @return {number} the value in miliseconds
- */
- function getElementTransitionDuration(element) {
- const propertyValue = getElementStyle(element, transitionProperty);
- const durationValue = getElementStyle(element, transitionDuration);
- const durationScale = durationValue.includes('ms') ? /* istanbul ignore next */1 : 1000;
- const duration = propertyValue && propertyValue !== 'none'
- ? parseFloat(durationValue) * durationScale : 0;
-
- return !Number.isNaN(duration) ? duration : /* istanbul ignore next */0;
- }
-
- /**
- * Shortcut for the `Element.dispatchEvent(Event)` method.
- *
- * @param {HTMLElement} element is the target
- * @param {Event} event is the `Event` object
- */
- const dispatchEvent = (element, event) => element.dispatchEvent(event);
-
- /**
- * Utility to make sure callbacks are consistently
- * called when transition ends.
- *
- * @param {HTMLElement} element target
- * @param {EventListener} handler `transitionend` callback
- */
- function emulateTransitionEnd(element, handler) {
- let called = 0;
- const endEvent = new Event(transitionEndEvent);
- const duration = getElementTransitionDuration(element);
- const delay = getElementTransitionDelay(element);
-
- if (duration) {
- /**
- * Wrap the handler in on -> off callback
- * @type {EventListener} e Event object
- */
- const transitionEndWrapper = (e) => {
- /* istanbul ignore else */
- if (e.target === element) {
- handler.apply(element, [e]);
- element.removeEventListener(transitionEndEvent, transitionEndWrapper);
- called = 1;
- }
- };
- element.addEventListener(transitionEndEvent, transitionEndWrapper);
- setTimeout(() => {
- /* istanbul ignore next */
- if (!called) dispatchEvent(element, endEvent);
- }, duration + delay + 17);
- } else {
- handler.apply(element, [endEvent]);
- }
- }
-
- /**
- * Checks if an object is a `Node`.
- *
- * @param {any} node the target object
- * @returns {boolean} the query result
- */
- const isNode = (element) => (element && [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
- .some((x) => +element.nodeType === x)) || false;
-
- /**
- * Check if a target object is `Window`.
- * => equivalent to `object instanceof Window`
- *
- * @param {any} object the target object
- * @returns {boolean} the query result
- */
- const isWindow = (object) => (object && object.constructor.name === 'Window') || false;
-
- /**
- * Checks if an object is a `Document`.
- * @see https://dom.spec.whatwg.org/#node
- *
- * @param {any} object the target object
- * @returns {boolean} the query result
- */
- const isDocument = (object) => (object && object.nodeType === 9) || false;
-
- /**
- * Returns the `document` or the `#document` element.
- * @see https://github.com/floating-ui/floating-ui
- * @param {(Node | Window)=} node
- * @returns {Document}
- */
- function getDocument(node) {
- // node instanceof Document
- if (isDocument(node)) return node;
- // node instanceof Node
- if (isNode(node)) return node.ownerDocument;
- // node instanceof Window
- if (isWindow(node)) return node.document;
- // node is undefined | NULL
- return window.document;
- }
-
- /**
- * Utility to check if target is typeof `HTMLElement`, `Element`, `Node`
- * or find one that matches a selector.
- *
- * @param {Node | string} selector the input selector or target element
- * @param {ParentNode=} parent optional node to look into
- * @return {HTMLElement?} the `HTMLElement` or `querySelector` result
- */
- function querySelector(selector, parent) {
- if (isNode(selector)) {
- return selector;
- }
- const lookUp = isNode(parent) ? parent : getDocument();
-
- return lookUp.querySelector(selector);
- }
-
- /**
- * Shortcut for `HTMLElement.closest` method which also works
- * with children of `ShadowRoot`. The order of the parameters
- * is intentional since they're both required.
- *
- * @see https://stackoverflow.com/q/54520554/803358
- *
- * @param {HTMLElement} element Element to look into
- * @param {string} selector the selector name
- * @return {HTMLElement?} the query result
- */
- function closest(element, selector) {
- return element ? (element.closest(selector)
- // break out of `ShadowRoot`
- || closest(element.getRootNode().host, selector)) : null;
- }
-
- /**
- * Shortcut for `Object.assign()` static method.
- * @param {Record<string, any>} obj a target object
- * @param {Record<string, any>} source a source object
- */
- const ObjectAssign = (obj, source) => Object.assign(obj, source);
-
- /**
- * Check class in `HTMLElement.classList`.
- *
- * @param {HTMLElement} element target
- * @param {string} classNAME to check
- * @returns {boolean}
- */
- function hasClass(element, classNAME) {
- return element.classList.contains(classNAME);
- }
-
- /**
- * Remove class from `HTMLElement.classList`.
- *
- * @param {HTMLElement} element target
- * @param {string} classNAME to remove
- * @returns {void}
- */
- function removeClass(element, classNAME) {
- element.classList.remove(classNAME);
- }
-
- /**
- * Checks if an element is an `HTMLElement`.
- * @see https://dom.spec.whatwg.org/#node
- *
- * @param {any} element the target object
- * @returns {boolean} the query result
- */
- const isHTMLElement = (element) => (element && element.nodeType === 1) || false;
-
- /** @type {Map<string, Map<HTMLElement, Record<string, any>>>} */
- const componentData = new Map();
- /**
- * An interface for web components background data.
- * @see https://github.com/thednp/bootstrap.native/blob/master/src/components/base-component.js
- */
- const Data = {
- /**
- * Sets web components data.
- * @param {HTMLElement} element target element
- * @param {string} component the component's name or a unique key
- * @param {Record<string, any>} instance the component instance
- */
- set: (element, component, instance) => {
- if (!isHTMLElement(element)) return;
-
- /* istanbul ignore else */
- if (!componentData.has(component)) {
- componentData.set(component, new Map());
- }
-
- const instanceMap = componentData.get(component);
- // not undefined, but defined right above
- instanceMap.set(element, instance);
- },
-
- /**
- * Returns all instances for specified component.
- * @param {string} component the component's name or a unique key
- * @returns {Map<HTMLElement, Record<string, any>>?} all the component instances
- */
- getAllFor: (component) => {
- const instanceMap = componentData.get(component);
-
- return instanceMap || null;
- },
-
- /**
- * Returns the instance associated with the target.
- * @param {HTMLElement} element target element
- * @param {string} component the component's name or a unique key
- * @returns {Record<string, any>?} the instance
- */
- get: (element, component) => {
- if (!isHTMLElement(element) || !component) return null;
- const allForC = Data.getAllFor(component);
- const instance = element && allForC && allForC.get(element);
-
- return instance || null;
- },
-
- /**
- * Removes web components data.
- * @param {HTMLElement} element target element
- * @param {string} component the component's name or a unique key
- */
- remove: (element, component) => {
- const instanceMap = componentData.get(component);
- if (!instanceMap || !isHTMLElement(element)) return;
-
- instanceMap.delete(element);
-
- /* istanbul ignore else */
- if (instanceMap.size === 0) {
- componentData.delete(component);
- }
- },
- };
-
- /**
- * An alias for `Data.get()`.
- * @type {SHORTY.getInstance<any>}
- */
- const getInstance = (target, component) => Data.get(target, component);
-
- /**
- * Checks if an object is an `Object`.
- *
- * @param {any} obj the target object
- * @returns {boolean} the query result
- */
- const isObject = (obj) => (typeof obj === 'object') || false;
-
- /**
- * Returns a namespaced `CustomEvent` specific to each component.
- * @param {string} EventType Event.type
- * @param {Record<string, any>=} config Event.options | Event.properties
- * @returns {SHORTY.OriginalEvent} a new namespaced event
- */
- function OriginalEvent(EventType, config) {
- const OriginalCustomEvent = new CustomEvent(EventType, {
- cancelable: true, bubbles: true,
- });
-
- /* istanbul ignore else */
- if (isObject(config)) {
- ObjectAssign(OriginalCustomEvent, config);
- }
- return OriginalCustomEvent;
- }
-
- /**
- * Global namespace for most components `fade` class.
- */
- const fadeClass = 'fade';
-
- /**
- * Global namespace for most components `show` class.
- */
- const showClass = 'show';
-
- /**
- * Global namespace for most components `dismiss` option.
- */
- const dataBsDismiss = 'data-bs-dismiss';
-
- /** @type {string} */
- const alertString = 'alert';
-
- /** @type {string} */
- const alertComponent = 'Alert';
-
- /**
- * Shortcut for `HTMLElement.getAttribute()` method.
- * @param {HTMLElement} element target element
- * @param {string} attribute attribute name
- * @returns {string?} attribute value
- */
- const getAttribute = (element, attribute) => element.getAttribute(attribute);
-
- /**
- * The raw value or a given component option.
- *
- * @typedef {string | HTMLElement | Function | number | boolean | null} niceValue
- */
-
- /**
- * Utility to normalize component options
- *
- * @param {any} value the input value
- * @return {niceValue} the normalized value
- */
- function normalizeValue(value) {
- if (['true', true].includes(value)) { // boolean
- // if ('true' === value) { // boolean
- return true;
- }
-
- if (['false', false].includes(value)) { // boolean
- // if ('false' === value) { // boolean
- return false;
- }
-
- if (value === '' || value === 'null') { // null
- return null;
- }
-
- if (value !== '' && !Number.isNaN(+value)) { // number
- return +value;
- }
-
- // string / function / HTMLElement / object
- return value;
- }
-
- /**
- * Shortcut for `Object.keys()` static method.
- * @param {Record<string, any>} obj a target object
- * @returns {string[]}
- */
- const ObjectKeys = (obj) => Object.keys(obj);
-
- /**
- * Shortcut for `String.toLowerCase()`.
- *
- * @param {string} source input string
- * @returns {string} lowercase output string
- */
- const toLowerCase = (source) => source.toLowerCase();
-
- /**
- * Utility to normalize component options.
- *
- * @param {HTMLElement} element target
- * @param {Record<string, any>} defaultOps component default options
- * @param {Record<string, any>} inputOps component instance options
- * @param {string=} ns component namespace
- * @return {Record<string, any>} normalized component options object
- */
- function normalizeOptions(element, defaultOps, inputOps, ns) {
- const data = { ...element.dataset };
- /** @type {Record<string, any>} */
- const normalOps = {};
- /** @type {Record<string, any>} */
- const dataOps = {};
- const title = 'title';
-
- ObjectKeys(data).forEach((k) => {
- const key = ns && k.includes(ns)
- ? k.replace(ns, '').replace(/[A-Z]/, (match) => toLowerCase(match))
- : k;
-
- dataOps[key] = normalizeValue(data[k]);
- });
-
- ObjectKeys(inputOps).forEach((k) => {
- inputOps[k] = normalizeValue(inputOps[k]);
- });
-
- ObjectKeys(defaultOps).forEach((k) => {
- /* istanbul ignore else */
- if (k in inputOps) {
- normalOps[k] = inputOps[k];
- } else if (k in dataOps) {
- normalOps[k] = dataOps[k];
- } else {
- normalOps[k] = k === title
- ? getAttribute(element, title)
- : defaultOps[k];
- }
- });
-
- return normalOps;
- }
-
- var version = "4.2.0";
-
- const Version = version;
-
- /* Native JavaScript for Bootstrap 5 | Base Component
- ----------------------------------------------------- */
-
- /** Returns a new `BaseComponent` instance. */
- class BaseComponent {
- /**
- * @param {HTMLElement | string} target `Element` or selector string
- * @param {BSN.ComponentOptions=} config component instance options
- */
- constructor(target, config) {
- const self = this;
- const element = querySelector(target);
-
- if (!element) {
- throw Error(`${self.name} Error: "${target}" is not a valid selector.`);
- }
-
- /** @static @type {BSN.ComponentOptions} */
- self.options = {};
-
- const prevInstance = Data.get(element, self.name);
- if (prevInstance) prevInstance.dispose();
-
- /** @type {HTMLElement} */
- self.element = element;
-
- /* istanbul ignore else */
- if (self.defaults && ObjectKeys(self.defaults).length) {
- self.options = normalizeOptions(element, self.defaults, (config || {}), 'bs');
- }
-
- Data.set(element, self.name, self);
- }
-
- /* eslint-disable */
- /* istanbul ignore next */
- /** @static */
- get version() { return Version; }
-
- /* eslint-enable */
- /* istanbul ignore next */
- /** @static */
- get name() { return this.constructor.name; }
-
- /* istanbul ignore next */
- /** @static */
- get defaults() { return this.constructor.defaults; }
-
- /**
- * Removes component from target element;
- */
- dispose() {
- const self = this;
- Data.remove(self.element, self.name);
- ObjectKeys(self).forEach((prop) => { self[prop] = null; });
- }
- }
-
- /* Native JavaScript for Bootstrap 5 | Alert
- -------------------------------------------- */
-
- // ALERT PRIVATE GC
- // ================
- const alertSelector = `.${alertString}`;
- const alertDismissSelector = `[${dataBsDismiss}="${alertString}"]`;
-
- /**
- * Static method which returns an existing `Alert` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Alert>}
- */
- const getAlertInstance = (element) => getInstance(element, alertComponent);
-
- /**
- * An `Alert` initialization callback.
- * @type {BSN.InitCallback<Alert>}
- */
- const alertInitCallback = (element) => new Alert(element);
-
- // ALERT CUSTOM EVENTS
- // ===================
- const closeAlertEvent = OriginalEvent(`close.bs.${alertString}`);
- const closedAlertEvent = OriginalEvent(`closed.bs.${alertString}`);
-
- // ALERT EVENT HANDLER
- // ===================
- /**
- * Alert `transitionend` callback.
- * @param {Alert} self target Alert instance
- */
- function alertTransitionEnd(self) {
- const { element } = self;
- toggleAlertHandler(self);
-
- dispatchEvent(element, closedAlertEvent);
-
- self.dispose();
- element.remove();
- }
-
- // ALERT PRIVATE METHOD
- // ====================
- /**
- * Toggle on / off the `click` event listener.
- * @param {Alert} self the target alert instance
- * @param {boolean=} add when `true`, event listener is added
- */
- function toggleAlertHandler(self, add) {
- const action = add ? addListener : removeListener;
- const { dismiss } = self;
- /* istanbul ignore else */
- if (dismiss) action(dismiss, mouseclickEvent, self.close);
- }
-
- // ALERT DEFINITION
- // ================
- /** Creates a new Alert instance. */
- class Alert extends BaseComponent {
- /** @param {HTMLElement | string} target element or selector */
- constructor(target) {
- super(target);
- // bind
- const self = this;
-
- // initialization element
- const { element } = self;
-
- // the dismiss button
- /** @static @type {HTMLElement?} */
- self.dismiss = querySelector(alertDismissSelector, element);
-
- // add event listener
- toggleAlertHandler(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return alertComponent; }
- /* eslint-enable */
-
- // ALERT PUBLIC METHODS
- // ====================
- /**
- * Public method that hides the `.alert` element from the user,
- * disposes the instance once animation is complete, then
- * removes the element from the DOM.
- *
- * @param {Event=} e most likely the `click` event
- * @this {Alert} the `Alert` instance or `EventTarget`
- */
- close(e) {
- const self = e ? getAlertInstance(closest(this, alertSelector)) : this;
- const { element } = self;
-
- /* istanbul ignore else */
- if (element && hasClass(element, showClass)) {
- dispatchEvent(element, closeAlertEvent);
- if (closeAlertEvent.defaultPrevented) return;
-
- removeClass(element, showClass);
-
- if (hasClass(element, fadeClass)) {
- emulateTransitionEnd(element, () => alertTransitionEnd(self));
- } else alertTransitionEnd(self);
- }
- }
-
- /** Remove the component from target element. */
- dispose() {
- toggleAlertHandler(this);
- super.dispose();
- }
- }
-
- ObjectAssign(Alert, {
- selector: alertSelector,
- init: alertInitCallback,
- getInstance: getAlertInstance,
- });
-
- /**
- * A global namespace for aria-pressed.
- * @type {string}
- */
- const ariaPressed = 'aria-pressed';
-
- /**
- * Shortcut for `HTMLElement.setAttribute()` method.
- * @param {HTMLElement} element target element
- * @param {string} attribute attribute name
- * @param {string} value attribute value
- * @returns {void}
- */
- const setAttribute = (element, attribute, value) => element.setAttribute(attribute, value);
-
- /**
- * Add class to `HTMLElement.classList`.
- *
- * @param {HTMLElement} element target
- * @param {string} classNAME to add
- * @returns {void}
- */
- function addClass(element, classNAME) {
- element.classList.add(classNAME);
- }
-
- /**
- * Global namespace for most components active class.
- */
- const activeClass = 'active';
-
- /**
- * Global namespace for most components `toggle` option.
- */
- const dataBsToggle = 'data-bs-toggle';
-
- /** @type {string} */
- const buttonString = 'button';
-
- /** @type {string} */
- const buttonComponent = 'Button';
-
- /* Native JavaScript for Bootstrap 5 | Button
- ---------------------------------------------*/
-
- // BUTTON PRIVATE GC
- // =================
- const buttonSelector = `[${dataBsToggle}="${buttonString}"]`;
-
- /**
- * Static method which returns an existing `Button` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Button>}
- */
- const getButtonInstance = (element) => getInstance(element, buttonComponent);
-
- /**
- * A `Button` initialization callback.
- * @type {BSN.InitCallback<Button>}
- */
- const buttonInitCallback = (element) => new Button(element);
-
- // BUTTON PRIVATE METHOD
- // =====================
- /**
- * Toggles on/off the `click` event listener.
- * @param {Button} self the `Button` instance
- * @param {boolean=} add when `true`, event listener is added
- */
- function toggleButtonHandler(self, add) {
- const action = add ? addListener : removeListener;
- action(self.element, mouseclickEvent, self.toggle);
- }
-
- // BUTTON DEFINITION
- // =================
- /** Creates a new `Button` instance. */
- class Button extends BaseComponent {
- /**
- * @param {HTMLElement | string} target usually a `.btn` element
- */
- constructor(target) {
- super(target);
- const self = this;
-
- // initialization element
- const { element } = self;
-
- // set initial state
- /** @type {boolean} */
- self.isActive = hasClass(element, activeClass);
- setAttribute(element, ariaPressed, `${!!self.isActive}`);
-
- // add event listener
- toggleButtonHandler(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return buttonComponent; }
- /* eslint-enable */
-
- // BUTTON PUBLIC METHODS
- // =====================
- /**
- * Toggles the state of the target button.
- * @param {MouseEvent} e usually `click` Event object
- */
- toggle(e) {
- if (e) e.preventDefault();
- const self = e ? getButtonInstance(this) : this;
- if (!self.element) return;
- const { element, isActive } = self;
-
- if (hasClass(element, 'disabled')) return;
-
- const action = isActive ? removeClass : addClass;
- action(element, activeClass);
- setAttribute(element, ariaPressed, isActive ? 'false' : 'true');
- self.isActive = hasClass(element, activeClass);
- }
-
- /** Removes the `Button` component from the target element. */
- dispose() {
- toggleButtonHandler(this);
- super.dispose();
- }
- }
-
- ObjectAssign(Button, {
- selector: buttonSelector,
- init: buttonInitCallback,
- getInstance: getButtonInstance,
- });
-
- /**
- * A global namespace for `mouseenter` event.
- * @type {string}
- */
- const mouseenterEvent = 'mouseenter';
-
- /**
- * A global namespace for `mouseleave` event.
- * @type {string}
- */
- const mouseleaveEvent = 'mouseleave';
-
- /**
- * A global namespace for `keydown` event.
- * @type {string}
- */
- const keydownEvent = 'keydown';
-
- /**
- * A global namespace for `ArrowLeft` key.
- * @type {string} e.which = 37 equivalent
- */
- const keyArrowLeft = 'ArrowLeft';
-
- /**
- * A global namespace for `ArrowRight` key.
- * @type {string} e.which = 39 equivalent
- */
- const keyArrowRight = 'ArrowRight';
-
- /**
- * A global namespace for `pointerdown` event.
- * @type {string}
- */
- const pointerdownEvent = 'pointerdown';
-
- /**
- * A global namespace for `pointermove` event.
- * @type {string}
- */
- const pointermoveEvent = 'pointermove';
-
- /**
- * A global namespace for `pointerup` event.
- * @type {string}
- */
- const pointerupEvent = 'pointerup';
-
- /**
- * Returns the bounding client rect of a target `HTMLElement`.
- *
- * @see https://github.com/floating-ui/floating-ui
- *
- * @param {HTMLElement} element event.target
- * @param {boolean=} includeScale when *true*, the target scale is also computed
- * @returns {SHORTY.BoundingClientRect} the bounding client rect object
- */
- function getBoundingClientRect(element, includeScale) {
- const {
- width, height, top, right, bottom, left,
- } = element.getBoundingClientRect();
- let scaleX = 1;
- let scaleY = 1;
-
- if (includeScale && isHTMLElement(element)) {
- const { offsetWidth, offsetHeight } = element;
- scaleX = offsetWidth > 0 ? Math.round(width) / offsetWidth
- : /* istanbul ignore next */1;
- scaleY = offsetHeight > 0 ? Math.round(height) / offsetHeight
- : /* istanbul ignore next */1;
- }
-
- return {
- width: width / scaleX,
- height: height / scaleY,
- top: top / scaleY,
- right: right / scaleX,
- bottom: bottom / scaleY,
- left: left / scaleX,
- x: left / scaleX,
- y: top / scaleY,
- };
- }
-
- /**
- * Returns the `document.documentElement` or the `<html>` element.
- *
- * @param {(Node | Window)=} node
- * @returns {HTMLHtmlElement}
- */
- function getDocumentElement(node) {
- return getDocument(node).documentElement;
- }
-
- /**
- * Utility to determine if an `HTMLElement`
- * is partially visible in viewport.
- *
- * @param {HTMLElement} element target
- * @return {boolean} the query result
- */
- const isElementInScrollRange = (element) => {
- if (!element || !isNode(element)) return false;
-
- const { top, bottom } = getBoundingClientRect(element);
- const { clientHeight } = getDocumentElement(element);
- return top <= clientHeight && bottom >= 0;
- };
-
- /**
- * Checks if a page is Right To Left.
- * @param {HTMLElement=} node the target
- * @returns {boolean} the query result
- */
- const isRTL = (node) => getDocumentElement(node).dir === 'rtl';
-
- /**
- * A shortcut for `(document|Element).querySelectorAll`.
- *
- * @param {string} selector the input selector
- * @param {ParentNode=} parent optional node to look into
- * @return {NodeListOf<HTMLElement>} the query result
- */
- function querySelectorAll(selector, parent) {
- const lookUp = isNode(parent) ? parent : getDocument();
- return lookUp.querySelectorAll(selector);
- }
-
- /**
- * Shortcut for `HTMLElement.getElementsByClassName` method. Some `Node` elements
- * like `ShadowRoot` do not support `getElementsByClassName`.
- *
- * @param {string} selector the class name
- * @param {ParentNode=} parent optional Element to look into
- * @return {HTMLCollectionOf<HTMLElement>} the 'HTMLCollection'
- */
- function getElementsByClassName(selector, parent) {
- const lookUp = isNode(parent) ? parent : getDocument();
- return lookUp.getElementsByClassName(selector);
- }
-
- /** @type {Map<HTMLElement, any>} */
- const TimeCache = new Map();
- /**
- * An interface for one or more `TimerHandler`s per `Element`.
- * @see https://github.com/thednp/navbar.js/
- */
- const Timer = {
- /**
- * Sets a new timeout timer for an element, or element -> key association.
- * @param {HTMLElement} element target element
- * @param {ReturnType<TimerHandler>} callback the callback
- * @param {number} delay the execution delay
- * @param {string=} key a unique key
- */
- set: (element, callback, delay, key) => {
- if (!isHTMLElement(element)) return;
-
- /* istanbul ignore else */
- if (key && key.length) {
- /* istanbul ignore else */
- if (!TimeCache.has(element)) {
- TimeCache.set(element, new Map());
- }
- const keyTimers = TimeCache.get(element);
- keyTimers.set(key, setTimeout(callback, delay));
- } else {
- TimeCache.set(element, setTimeout(callback, delay));
- }
- },
-
- /**
- * Returns the timer associated with the target.
- * @param {HTMLElement} element target element
- * @param {string=} key a unique
- * @returns {number?} the timer
- */
- get: (element, key) => {
- if (!isHTMLElement(element)) return null;
- const keyTimers = TimeCache.get(element);
-
- if (key && key.length && keyTimers && keyTimers.get) {
- return keyTimers.get(key) || /* istanbul ignore next */null;
- }
- return keyTimers || null;
- },
-
- /**
- * Clears the element's timer.
- * @param {HTMLElement} element target element
- * @param {string=} key a unique key
- */
- clear: (element, key) => {
- if (!isHTMLElement(element)) return;
-
- if (key && key.length) {
- const keyTimers = TimeCache.get(element);
- /* istanbul ignore else */
- if (keyTimers && keyTimers.get) {
- clearTimeout(keyTimers.get(key));
- keyTimers.delete(key);
- /* istanbul ignore else */
- if (keyTimers.size === 0) {
- TimeCache.delete(element);
- }
- }
- } else {
- clearTimeout(TimeCache.get(element));
- TimeCache.delete(element);
- }
- },
- };
-
- /**
- * Utility to force re-paint of an `HTMLElement` target.
- *
- * @param {HTMLElement} element is the target
- * @return {number} the `Element.offsetHeight` value
- */
- const reflow = (element) => element.offsetHeight;
-
- /**
- * A global namespace for most scroll event listeners.
- * @type {Partial<AddEventListenerOptions>}
- */
- const passiveHandler = { passive: true };
-
- /**
- * Global namespace for most components `target` option.
- */
- const dataBsTarget = 'data-bs-target';
-
- /** @type {string} */
- const carouselString = 'carousel';
-
- /** @type {string} */
- const carouselComponent = 'Carousel';
-
- /**
- * Global namespace for most components `parent` option.
- */
- const dataBsParent = 'data-bs-parent';
-
- /**
- * Global namespace for most components `container` option.
- */
- const dataBsContainer = 'data-bs-container';
-
- /**
- * Returns the `Element` that THIS one targets
- * via `data-bs-target`, `href`, `data-bs-parent` or `data-bs-container`.
- *
- * @param {HTMLElement} element the target element
- * @returns {HTMLElement?} the query result
- */
- function getTargetElement(element) {
- const targetAttr = [dataBsTarget, dataBsParent, dataBsContainer, 'href'];
- const doc = getDocument(element);
-
- return targetAttr.map((att) => {
- const attValue = getAttribute(element, att);
- if (attValue) {
- return att === dataBsParent ? closest(element, attValue) : querySelector(attValue, doc);
- }
- return null;
- }).filter((x) => x)[0];
- }
-
- /* Native JavaScript for Bootstrap 5 | Carousel
- ----------------------------------------------- */
-
- // CAROUSEL PRIVATE GC
- // ===================
- const carouselSelector = `[data-bs-ride="${carouselString}"]`;
- const carouselItem = `${carouselString}-item`;
- const dataBsSlideTo = 'data-bs-slide-to';
- const dataBsSlide = 'data-bs-slide';
- const pausedClass = 'paused';
-
- const carouselDefaults = {
- pause: 'hover',
- keyboard: false,
- touch: true,
- interval: 5000,
- };
-
- /**
- * Static method which returns an existing `Carousel` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Carousel>}
- */
- const getCarouselInstance = (element) => getInstance(element, carouselComponent);
-
- /**
- * A `Carousel` initialization callback.
- * @type {BSN.InitCallback<Carousel>}
- */
- const carouselInitCallback = (element) => new Carousel(element);
-
- let startX = 0;
- let currentX = 0;
- let endX = 0;
-
- // CAROUSEL CUSTOM EVENTS
- // ======================
- const carouselSlideEvent = OriginalEvent(`slide.bs.${carouselString}`);
- const carouselSlidEvent = OriginalEvent(`slid.bs.${carouselString}`);
-
- // CAROUSEL EVENT HANDLERS
- // =======================
- /**
- * The `transitionend` event listener of the `Carousel`.
- * @param {Carousel} self the `Carousel` instance
- */
- function carouselTransitionEndHandler(self) {
- const {
- index, direction, element, slides, options,
- } = self;
-
- // discontinue disposed instances
- /* istanbul ignore else */
- if (self.isAnimating && getCarouselInstance(element)) {
- const activeItem = getActiveIndex(self);
- const orientation = direction === 'left' ? 'next' : 'prev';
- const directionClass = direction === 'left' ? 'start' : 'end';
-
- addClass(slides[index], activeClass);
- removeClass(slides[index], `${carouselItem}-${orientation}`);
- removeClass(slides[index], `${carouselItem}-${directionClass}`);
-
- removeClass(slides[activeItem], activeClass);
- removeClass(slides[activeItem], `${carouselItem}-${directionClass}`);
-
- dispatchEvent(element, carouselSlidEvent);
- Timer.clear(element, dataBsSlide);
-
- // check for element, might have been disposed
- if (!getDocument(element).hidden && options.interval
- && !self.isPaused) {
- self.cycle();
- }
- }
- }
-
- /**
- * Handles the `mouseenter` events when *options.pause*
- * is set to `hover`.
- *
- * @this {HTMLElement}
- */
- function carouselPauseHandler() {
- const element = this;
- const self = getCarouselInstance(element);
- /* istanbul ignore else */
- if (self && !self.isPaused && !Timer.get(element, pausedClass)) {
- addClass(element, pausedClass);
- }
- }
-
- /**
- * Handles the `mouseleave` events when *options.pause*
- * is set to `hover`.
- *
- * @this {HTMLElement}
- */
- function carouselResumeHandler() {
- const element = this;
- const self = getCarouselInstance(element);
- /* istanbul ignore else */
- if (self && self.isPaused && !Timer.get(element, pausedClass)) {
- self.cycle();
- }
- }
-
- /**
- * Handles the `click` event for the `Carousel` indicators.
- *
- * @this {HTMLElement}
- * @param {MouseEvent} e the `Event` object
- */
- function carouselIndicatorHandler(e) {
- e.preventDefault();
- const indicator = this;
- const element = closest(indicator, carouselSelector) || getTargetElement(indicator);
- const self = getCarouselInstance(element);
-
- if (!self || self.isAnimating) return;
-
- const newIndex = +getAttribute(indicator, dataBsSlideTo);
-
- if (indicator && !hasClass(indicator, activeClass) // event target is not active
- && !Number.isNaN(newIndex)) { // AND has the specific attribute
- self.to(newIndex); // do the slide
- }
- }
-
- /**
- * Handles the `click` event for the `Carousel` arrows.
- *
- * @this {HTMLElement}
- * @param {MouseEvent} e the `Event` object
- */
- function carouselControlsHandler(e) {
- e.preventDefault();
- const control = this;
- const element = closest(control, carouselSelector) || getTargetElement(control);
- const self = getCarouselInstance(element);
-
- if (!self || self.isAnimating) return;
- const orientation = getAttribute(control, dataBsSlide);
-
- /* istanbul ignore else */
- if (orientation === 'next') {
- self.next();
- } else if (orientation === 'prev') {
- self.prev();
- }
- }
-
- /**
- * Handles the keyboard `keydown` event for the visible `Carousel` elements.
- *
- * @param {KeyboardEvent} e the `Event` object
- */
- function carouselKeyHandler({ code, target }) {
- const doc = getDocument(target);
- const [element] = [...querySelectorAll(carouselSelector, doc)]
- .filter((x) => isElementInScrollRange(x));
- const self = getCarouselInstance(element);
-
- /* istanbul ignore next */
- if (!self || self.isAnimating || /textarea|input/i.test(target.tagName)) return;
- const RTL = isRTL(element);
- const arrowKeyNext = !RTL ? keyArrowRight : keyArrowLeft;
- const arrowKeyPrev = !RTL ? keyArrowLeft : keyArrowRight;
-
- /* istanbul ignore else */
- if (code === arrowKeyPrev) self.prev();
- else if (code === arrowKeyNext) self.next();
- }
-
- // CAROUSEL TOUCH HANDLERS
- // =======================
- /**
- * Handles the `pointerdown` event for the `Carousel` element.
- *
- * @this {HTMLElement}
- * @param {PointerEvent} e the `Event` object
- */
- function carouselPointerDownHandler(e) {
- const element = this;
- const { target } = e;
- const self = getCarouselInstance(element);
-
- // filter pointer event on controls & indicators
- const { controls, indicators } = self;
- if ([...controls, ...indicators].some((el) => (el === target || el.contains(target)))) {
- return;
- }
-
- if (!self || self.isAnimating || self.isTouch) { return; }
-
- startX = e.pageX;
-
- /* istanbul ignore else */
- if (element.contains(target)) {
- self.isTouch = true;
- toggleCarouselTouchHandlers(self, true);
- }
- }
-
- /**
- * Handles the `pointermove` event for the `Carousel` element.
- *
- * @this {HTMLElement}
- * @param {PointerEvent} e
- */
- function carouselPointerMoveHandler(e) {
- // const self = getCarouselInstance(this);
-
- // if (!self || !self.isTouch) { return; }
-
- currentX = e.pageX;
- }
-
- /**
- * Handles the `pointerup` event for the `Carousel` element.
- *
- * @this {HTMLElement}
-
- * @param {PointerEvent} e
- */
- function carouselPointerUpHandler(e) {
- const { target } = e;
- const doc = getDocument(target);
- const self = [...querySelectorAll(carouselSelector, doc)]
- .map((c) => getCarouselInstance(c)).find((i) => i.isTouch);
-
- // impossible to satisfy
- /* istanbul ignore next */
- if (!self) { return; }
-
- const { element, index } = self;
- const RTL = isRTL(target);
-
- self.isTouch = false;
- toggleCarouselTouchHandlers(self);
-
- if (doc.getSelection().toString().length) {
- // reset pointer position
- startX = 0; currentX = 0; endX = 0;
- return;
- }
-
- endX = e.pageX;
-
- // the event target is outside the carousel context
- // OR swipe distance is less than 120px
- /* istanbul ignore else */
- if (!element.contains(target) || Math.abs(startX - endX) < 120) {
- // reset pointer position
- startX = 0; currentX = 0; endX = 0;
- return;
- }
- // OR determine next index to slide to
- /* istanbul ignore else */
- if (currentX < startX) {
- self.to(index + (RTL ? -1 : 1));
- } else if (currentX > startX) {
- self.to(index + (RTL ? 1 : -1));
- }
- // reset pointer position
- startX = 0; currentX = 0; endX = 0;
- }
-
- // CAROUSEL PRIVATE METHODS
- // ========================
- /**
- * Sets active indicator for the `Carousel` instance.
- * @param {Carousel} self the `Carousel` instance
- * @param {number} pageIndex the index of the new active indicator
- */
- function activateCarouselIndicator(self, pageIndex) {
- const { indicators } = self;
- [...indicators].forEach((x) => removeClass(x, activeClass));
-
- /* istanbul ignore else */
- if (self.indicators[pageIndex]) addClass(indicators[pageIndex], activeClass);
- }
-
- /**
- * Toggles the pointer event listeners for a given `Carousel` instance.
- * @param {Carousel} self the `Carousel` instance
- * @param {boolean=} add when `TRUE` event listeners are added
- */
- function toggleCarouselTouchHandlers(self, add) {
- const { element } = self;
- const action = add ? addListener : removeListener;
- action(getDocument(element), pointermoveEvent, carouselPointerMoveHandler, passiveHandler);
- action(getDocument(element), pointerupEvent, carouselPointerUpHandler, passiveHandler);
- }
-
- /**
- * Toggles all event listeners for a given `Carousel` instance.
- * @param {Carousel} self the `Carousel` instance
- * @param {boolean=} add when `TRUE` event listeners are added
- */
- function toggleCarouselHandlers(self, add) {
- const {
- element, options, slides, controls, indicators,
- } = self;
- const {
- touch, pause, interval, keyboard,
- } = options;
- const action = add ? addListener : removeListener;
-
- if (pause && interval) {
- action(element, mouseenterEvent, carouselPauseHandler);
- action(element, mouseleaveEvent, carouselResumeHandler);
- }
-
- if (touch && slides.length > 2) {
- action(element, pointerdownEvent, carouselPointerDownHandler, passiveHandler);
- }
-
- /* istanbul ignore else */
- if (controls.length) {
- controls.forEach((arrow) => {
- /* istanbul ignore else */
- if (arrow) action(arrow, mouseclickEvent, carouselControlsHandler);
- });
- }
-
- /* istanbul ignore else */
- if (indicators.length) {
- indicators.forEach((indicator) => {
- action(indicator, mouseclickEvent, carouselIndicatorHandler);
- });
- }
-
- if (keyboard) action(getDocument(element), keydownEvent, carouselKeyHandler);
- }
-
- /**
- * Returns the index of the current active item.
- * @param {Carousel} self the `Carousel` instance
- * @returns {number} the query result
- */
- function getActiveIndex(self) {
- const { slides, element } = self;
- const activeItem = querySelector(`.${carouselItem}.${activeClass}`, element);
- return [...slides].indexOf(activeItem);
- }
-
- // CAROUSEL DEFINITION
- // ===================
- /** Creates a new `Carousel` instance. */
- class Carousel extends BaseComponent {
- /**
- * @param {HTMLElement | string} target mostly a `.carousel` element
- * @param {BSN.Options.Carousel=} config instance options
- */
- constructor(target, config) {
- super(target, config);
- // bind
- const self = this;
- // initialization element
- const { element } = self;
-
- // additional properties
- /** @type {string} */
- self.direction = isRTL(element) ? 'right' : 'left';
- /** @type {number} */
- self.index = 0;
- /** @type {boolean} */
- self.isTouch = false;
-
- // carousel elements
- // a LIVE collection is prefferable
- self.slides = getElementsByClassName(carouselItem, element);
- const { slides } = self;
-
- // invalidate when not enough items
- // no need to go further
- if (slides.length < 2) { return; }
- // external controls must be within same document context
- const doc = getDocument(element);
-
- self.controls = [
- ...querySelectorAll(`[${dataBsSlide}]`, element),
- ...querySelectorAll(`[${dataBsSlide}][${dataBsTarget}="#${element.id}"]`, doc),
- ];
-
- /** @type {HTMLElement?} */
- self.indicator = querySelector(`.${carouselString}-indicators`, element);
-
- // a LIVE collection is prefferable
- /** @type {HTMLElement[]} */
- self.indicators = [
- ...(self.indicator ? querySelectorAll(`[${dataBsSlideTo}]`, self.indicator) : []),
- ...querySelectorAll(`[${dataBsSlideTo}][${dataBsTarget}="#${element.id}"]`, doc),
- ];
-
- // set JavaScript and DATA API options
- const { options } = self;
-
- // don't use TRUE as interval, it's actually 0, use the default 5000ms better
- self.options.interval = options.interval === true
- ? carouselDefaults.interval
- : options.interval;
-
- // set first slide active if none
- /* istanbul ignore else */
- if (getActiveIndex(self) < 0) {
- addClass(slides[0], activeClass);
- /* istanbul ignore else */
- if (self.indicators.length) activateCarouselIndicator(self, 0);
- }
-
- // attach event handlers
- toggleCarouselHandlers(self, true);
-
- // start to cycle if interval is set
- if (options.interval) self.cycle();
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return carouselComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return carouselDefaults; }
- /* eslint-enable */
-
- /**
- * Check if instance is paused.
- * @returns {boolean}
- */
- get isPaused() {
- return hasClass(this.element, pausedClass);
- }
-
- /**
- * Check if instance is animating.
- * @returns {boolean}
- */
- get isAnimating() {
- return querySelector(`.${carouselItem}-next,.${carouselItem}-prev`, this.element) !== null;
- }
-
- // CAROUSEL PUBLIC METHODS
- // =======================
- /** Slide automatically through items. */
- cycle() {
- const self = this;
- const {
- element, options, isPaused, index,
- } = self;
-
- Timer.clear(element, carouselString);
- if (isPaused) {
- Timer.clear(element, pausedClass);
- removeClass(element, pausedClass);
- }
-
- Timer.set(element, () => {
- // it's very important to check self.element
- // where instance might have been disposed
- /* istanbul ignore else */
- if (self.element && !self.isPaused && !self.isTouch
- && isElementInScrollRange(element)) {
- self.to(index + 1);
- }
- }, options.interval, carouselString);
- }
-
- /** Pause the automatic cycle. */
- pause() {
- const self = this;
- const { element, options } = self;
- /* istanbul ignore else */
- if (!self.isPaused && options.interval) {
- addClass(element, pausedClass);
- Timer.set(element, () => {}, 1, pausedClass);
- }
- }
-
- /** Slide to the next item. */
- next() {
- const self = this;
- /* istanbul ignore else */
- if (!self.isAnimating) { self.to(self.index + 1); }
- }
-
- /** Slide to the previous item. */
- prev() {
- const self = this;
- /* istanbul ignore else */
- if (!self.isAnimating) { self.to(self.index - 1); }
- }
-
- /**
- * Jump to the item with the `idx` index.
- * @param {number} idx the index of the item to jump to
- */
- to(idx) {
- const self = this;
- const {
- element, slides, options,
- } = self;
- const activeItem = getActiveIndex(self);
- const RTL = isRTL(element);
- let next = idx;
-
- // when controled via methods, make sure to check again
- // first return if we're on the same item #227
- // `to()` must be SPAM protected by Timer
- if (self.isAnimating || activeItem === next || Timer.get(element, dataBsSlide)) return;
-
- // determine transition direction
- /* istanbul ignore else */
- if ((activeItem < next) || (activeItem === 0 && next === slides.length - 1)) {
- self.direction = RTL ? 'right' : 'left'; // next
- } else if ((activeItem > next) || (activeItem === slides.length - 1 && next === 0)) {
- self.direction = RTL ? 'left' : 'right'; // prev
- }
- const { direction } = self;
-
- // find the right next index
- if (next < 0) { next = slides.length - 1; } else if (next >= slides.length) { next = 0; }
-
- // orientation, class name, eventProperties
- const orientation = direction === 'left' ? 'next' : 'prev';
- const directionClass = direction === 'left' ? 'start' : 'end';
-
- const eventProperties = {
- relatedTarget: slides[next],
- from: activeItem,
- to: next,
- direction,
- };
-
- // update event properties
- ObjectAssign(carouselSlideEvent, eventProperties);
- ObjectAssign(carouselSlidEvent, eventProperties);
-
- // discontinue when prevented
- dispatchEvent(element, carouselSlideEvent);
- if (carouselSlideEvent.defaultPrevented) return;
-
- // update index
- self.index = next;
- activateCarouselIndicator(self, next);
-
- if (getElementTransitionDuration(slides[next]) && hasClass(element, 'slide')) {
- Timer.set(element, () => {
- addClass(slides[next], `${carouselItem}-${orientation}`);
- reflow(slides[next]);
- addClass(slides[next], `${carouselItem}-${directionClass}`);
- addClass(slides[activeItem], `${carouselItem}-${directionClass}`);
-
- emulateTransitionEnd(slides[next], () => carouselTransitionEndHandler(self));
- }, 0, dataBsSlide);
- } else {
- addClass(slides[next], activeClass);
- removeClass(slides[activeItem], activeClass);
-
- Timer.set(element, () => {
- Timer.clear(element, dataBsSlide);
- // check for element, might have been disposed
- /* istanbul ignore else */
- if (element && options.interval && !self.isPaused) {
- self.cycle();
- }
-
- dispatchEvent(element, carouselSlidEvent);
- }, 0, dataBsSlide);
- }
- }
-
- /** Remove `Carousel` component from target. */
- dispose() {
- const self = this;
- const { slides } = self;
- const itemClasses = ['start', 'end', 'prev', 'next'];
-
- [...slides].forEach((slide, idx) => {
- if (hasClass(slide, activeClass)) activateCarouselIndicator(self, idx);
- itemClasses.forEach((c) => removeClass(slide, `${carouselItem}-${c}`));
- });
-
- toggleCarouselHandlers(self);
- super.dispose();
- }
- }
-
- ObjectAssign(Carousel, {
- selector: carouselSelector,
- init: carouselInitCallback,
- getInstance: getCarouselInstance,
- });
-
- /**
- * A global namespace for aria-expanded.
- * @type {string}
- */
- const ariaExpanded = 'aria-expanded';
-
- /**
- * Shortcut for `Object.entries()` static method.
- * @param {Record<string, any>} obj a target object
- * @returns {[string, any][]}
- */
- const ObjectEntries = (obj) => Object.entries(obj);
-
- /**
- * Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
- * @param {HTMLElement} element target element
- * @param {Partial<CSSStyleDeclaration>} styles attribute value
- */
- const setElementStyle = (element, styles) => {
- ObjectEntries(styles).forEach(([key, value]) => {
- if (key.includes('--')) {
- element.style.setProperty(key, value);
- } else {
- const propObject = {}; propObject[key] = value;
- ObjectAssign(element.style, propObject);
- }
- });
- };
-
- /**
- * Global namespace for most components `collapsing` class.
- * As used by `Collapse` / `Tab`.
- */
- const collapsingClass = 'collapsing';
-
- /** @type {string} */
- const collapseString = 'collapse';
-
- /** @type {string} */
- const collapseComponent = 'Collapse';
-
- /* Native JavaScript for Bootstrap 5 | Collapse
- ----------------------------------------------- */
-
- // COLLAPSE GC
- // ===========
- const collapseSelector = `.${collapseString}`;
- const collapseToggleSelector = `[${dataBsToggle}="${collapseString}"]`;
- const collapseDefaults = { parent: null };
-
- /**
- * Static method which returns an existing `Collapse` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Collapse>}
- */
- const getCollapseInstance = (element) => getInstance(element, collapseComponent);
-
- /**
- * A `Collapse` initialization callback.
- * @type {BSN.InitCallback<Collapse>}
- */
- const collapseInitCallback = (element) => new Collapse(element);
-
- // COLLAPSE CUSTOM EVENTS
- // ======================
- const showCollapseEvent = OriginalEvent(`show.bs.${collapseString}`);
- const shownCollapseEvent = OriginalEvent(`shown.bs.${collapseString}`);
- const hideCollapseEvent = OriginalEvent(`hide.bs.${collapseString}`);
- const hiddenCollapseEvent = OriginalEvent(`hidden.bs.${collapseString}`);
-
- // COLLAPSE PRIVATE METHODS
- // ========================
- /**
- * Expand the designated `Element`.
- * @param {Collapse} self the `Collapse` instance
- */
- function expandCollapse(self) {
- const {
- element, parent, triggers,
- } = self;
-
- dispatchEvent(element, showCollapseEvent);
- if (showCollapseEvent.defaultPrevented) return;
-
- Timer.set(element, () => {}, 17);
- if (parent) Timer.set(parent, () => {}, 17);
-
- addClass(element, collapsingClass);
- removeClass(element, collapseString);
-
- setElementStyle(element, { height: `${element.scrollHeight}px` });
-
- emulateTransitionEnd(element, () => {
- Timer.clear(element);
- if (parent) Timer.clear(parent);
-
- triggers.forEach((btn) => setAttribute(btn, ariaExpanded, 'true'));
-
- removeClass(element, collapsingClass);
- addClass(element, collapseString);
- addClass(element, showClass);
-
- setElementStyle(element, { height: '' });
-
- dispatchEvent(element, shownCollapseEvent);
- });
- }
-
- /**
- * Collapse the designated `Element`.
- * @param {Collapse} self the `Collapse` instance
- */
- function collapseContent(self) {
- const {
- element, parent, triggers,
- } = self;
-
- dispatchEvent(element, hideCollapseEvent);
-
- if (hideCollapseEvent.defaultPrevented) return;
-
- Timer.set(element, () => {}, 17);
- if (parent) Timer.set(parent, () => {}, 17);
-
- setElementStyle(element, { height: `${element.scrollHeight}px` });
-
- removeClass(element, collapseString);
- removeClass(element, showClass);
- addClass(element, collapsingClass);
-
- reflow(element);
- setElementStyle(element, { height: '0px' });
-
- emulateTransitionEnd(element, () => {
- Timer.clear(element);
- /* istanbul ignore else */
- if (parent) Timer.clear(parent);
-
- triggers.forEach((btn) => setAttribute(btn, ariaExpanded, 'false'));
-
- removeClass(element, collapsingClass);
- addClass(element, collapseString);
-
- setElementStyle(element, { height: '' });
-
- dispatchEvent(element, hiddenCollapseEvent);
- });
- }
-
- /**
- * Toggles on/off the event listener(s) of the `Collapse` instance.
- * @param {Collapse} self the `Collapse` instance
- * @param {boolean=} add when `true`, the event listener is added
- */
- function toggleCollapseHandler(self, add) {
- const action = add ? addListener : removeListener;
- const { triggers } = self;
-
- /* istanbul ignore else */
- if (triggers.length) {
- triggers.forEach((btn) => action(btn, mouseclickEvent, collapseClickHandler));
- }
- }
-
- // COLLAPSE EVENT HANDLER
- // ======================
- /**
- * Handles the `click` event for the `Collapse` instance.
- * @param {MouseEvent} e the `Event` object
- */
- function collapseClickHandler(e) {
- const { target } = e; // our target is `HTMLElement`
- const trigger = target && closest(target, collapseToggleSelector);
- const element = trigger && getTargetElement(trigger);
- const self = element && getCollapseInstance(element);
- /* istanbul ignore else */
- if (self) self.toggle();
-
- // event target is anchor link #398
- if (trigger && trigger.tagName === 'A') e.preventDefault();
- }
-
- // COLLAPSE DEFINITION
- // ===================
-
- /** Returns a new `Colapse` instance. */
- class Collapse extends BaseComponent {
- /**
- * @param {HTMLElement | string} target and `Element` that matches the selector
- * @param {BSN.Options.Collapse=} config instance options
- */
- constructor(target, config) {
- super(target, config);
- // bind
- const self = this;
-
- // initialization element
- const { element, options } = self;
- const doc = getDocument(element);
-
- // set triggering elements
- /** @type {HTMLElement[]} */
- self.triggers = [...querySelectorAll(collapseToggleSelector, doc)]
- .filter((btn) => getTargetElement(btn) === element);
-
- // set parent accordion
- /** @type {HTMLElement?} */
- self.parent = querySelector(options.parent, doc)
- || getTargetElement(element) || null;
-
- // add event listeners
- toggleCollapseHandler(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return collapseComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return collapseDefaults; }
- /* eslint-enable */
-
- // COLLAPSE PUBLIC METHODS
- // =======================
- /** Toggles the visibility of the collapse. */
- toggle() {
- const self = this;
- if (!hasClass(self.element, showClass)) self.show();
- else self.hide();
- }
-
- /** Hides the collapse. */
- hide() {
- const self = this;
- const { triggers, element } = self;
- if (Timer.get(element)) return;
-
- collapseContent(self);
- /* istanbul ignore else */
- if (triggers.length) {
- triggers.forEach((btn) => addClass(btn, `${collapseString}d`));
- }
- }
-
- /** Shows the collapse. */
- show() {
- const self = this;
- const {
- element, parent, triggers,
- } = self;
- let activeCollapse;
- let activeCollapseInstance;
-
- if (parent) {
- activeCollapse = [...querySelectorAll(`.${collapseString}.${showClass}`, parent)]
- .find((i) => getCollapseInstance(i));
- activeCollapseInstance = activeCollapse && getCollapseInstance(activeCollapse);
- }
-
- if ((!parent || !Timer.get(parent)) && !Timer.get(element)) {
- if (activeCollapseInstance && activeCollapse !== element) {
- collapseContent(activeCollapseInstance);
- activeCollapseInstance.triggers.forEach((btn) => {
- addClass(btn, `${collapseString}d`);
- });
- }
-
- expandCollapse(self);
- /* istanbul ignore else */
- if (triggers.length) {
- triggers.forEach((btn) => removeClass(btn, `${collapseString}d`));
- }
- }
- }
-
- /** Remove the `Collapse` component from the target `Element`. */
- dispose() {
- const self = this;
- toggleCollapseHandler(self);
-
- super.dispose();
- }
- }
-
- ObjectAssign(Collapse, {
- selector: collapseSelector,
- init: collapseInitCallback,
- getInstance: getCollapseInstance,
- });
-
- /**
- * A global namespace for `focus` event.
- * @type {string}
- */
- const focusEvent = 'focus';
-
- /**
- * A global namespace for `keyup` event.
- * @type {string}
- */
- const keyupEvent = 'keyup';
-
- /**
- * A global namespace for `scroll` event.
- * @type {string}
- */
- const scrollEvent = 'scroll';
-
- /**
- * A global namespace for `resize` event.
- * @type {string}
- */
- const resizeEvent = 'resize';
-
- /**
- * A global namespace for `ArrowUp` key.
- * @type {string} e.which = 38 equivalent
- */
- const keyArrowUp = 'ArrowUp';
-
- /**
- * A global namespace for `ArrowDown` key.
- * @type {string} e.which = 40 equivalent
- */
- const keyArrowDown = 'ArrowDown';
-
- /**
- * A global namespace for `Escape` key.
- * @type {string} e.which = 27 equivalent
- */
- const keyEscape = 'Escape';
-
- /**
- * Shortcut for `HTMLElement.hasAttribute()` method.
- * @param {HTMLElement} element target element
- * @param {string} attribute attribute name
- * @returns {boolean} the query result
- */
- const hasAttribute = (element, attribute) => element.hasAttribute(attribute);
-
- /**
- * Utility to focus an `HTMLElement` target.
- *
- * @param {HTMLElement} element is the target
- */
- const focus = (element) => element.focus();
-
- /**
- * Returns the `Window` object of a target node.
- * @see https://github.com/floating-ui/floating-ui
- *
- * @param {(Node | Window)=} node target node
- * @returns {Window} the `Window` object
- */
- function getWindow(node) {
- // node is undefined | NULL
- if (!node) return window;
- // node instanceof Document
- if (isDocument(node)) return node.defaultView;
- // node instanceof Node
- if (isNode(node)) return node.ownerDocument.defaultView;
- // node is instanceof Window
- return node;
- }
-
- /**
- * Global namespace for `Dropdown` types / classes.
- */
- const dropdownMenuClasses = ['dropdown', 'dropup', 'dropstart', 'dropend'];
-
- /** @type {string} */
- const dropdownComponent = 'Dropdown';
-
- /**
- * Global namespace for `.dropdown-menu`.
- */
- const dropdownMenuClass = 'dropdown-menu';
-
- /**
- * Checks if an *event.target* or its parent has an `href="#"` value.
- * We need to prevent jumping around onclick, don't we?
- *
- * @param {Node} element the target element
- * @returns {boolean} the query result
- */
- function isEmptyAnchor(element) {
- // `EventTarget` must be `HTMLElement`
- const parentAnchor = closest(element, 'A');
- return isHTMLElement(element)
- // anchor href starts with #
- && ((hasAttribute(element, 'href') && element.href.slice(-1) === '#')
- // OR a child of an anchor with href starts with #
- || (parentAnchor && hasAttribute(parentAnchor, 'href')
- && parentAnchor.href.slice(-1) === '#'));
- }
-
- /* Native JavaScript for Bootstrap 5 | Dropdown
- ----------------------------------------------- */
-
- // DROPDOWN PRIVATE GC
- // ===================
- const [
- dropdownString,
- dropupString,
- dropstartString,
- dropendString,
- ] = dropdownMenuClasses;
- const dropdownSelector = `[${dataBsToggle}="${dropdownString}"]`;
-
- /**
- * Static method which returns an existing `Dropdown` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Dropdown>}
- */
- const getDropdownInstance = (element) => getInstance(element, dropdownComponent);
-
- /**
- * A `Dropdown` initialization callback.
- * @type {BSN.InitCallback<Dropdown>}
- */
- const dropdownInitCallback = (element) => new Dropdown(element);
-
- // DROPDOWN PRIVATE GC
- // ===================
- // const dropdownMenuStartClass = `${dropdownMenuClass}-start`;
- const dropdownMenuEndClass = `${dropdownMenuClass}-end`;
- const verticalClass = [dropdownString, dropupString];
- const horizontalClass = [dropstartString, dropendString];
- const menuFocusTags = ['A', 'BUTTON'];
-
- const dropdownDefaults = {
- offset: 5, // [number] 5(px)
- display: 'dynamic', // [dynamic|static]
- };
-
- // DROPDOWN CUSTOM EVENTS
- // ======================
- const showDropdownEvent = OriginalEvent(`show.bs.${dropdownString}`);
- const shownDropdownEvent = OriginalEvent(`shown.bs.${dropdownString}`);
- const hideDropdownEvent = OriginalEvent(`hide.bs.${dropdownString}`);
- const hiddenDropdownEvent = OriginalEvent(`hidden.bs.${dropdownString}`);
-
- // DROPDOWN PRIVATE METHODS
- // ========================
- /**
- * Apply specific style or class names to a `.dropdown-menu` to automatically
- * accomodate the layout and the page scroll.
- *
- * @param {Dropdown} self the `Dropdown` instance
- */
- function styleDropdown(self) {
- const {
- element, menu, parentElement, options,
- } = self;
- const { offset } = options;
-
- // don't apply any style on mobile view
- /* istanbul ignore next: this test requires a navbar */
- if (getElementStyle(menu, 'position') === 'static') return;
-
- const RTL = isRTL(element);
- // const menuStart = hasClass(menu, dropdownMenuStartClass);
- const menuEnd = hasClass(menu, dropdownMenuEndClass);
-
- // reset menu offset and position
- const resetProps = ['margin', 'top', 'bottom', 'left', 'right'];
- resetProps.forEach((p) => { menu.style[p] = ''; });
-
- // set initial position class
- // take into account .btn-group parent as .dropdown
- // this requires navbar/btn-group/input-group
- let positionClass = dropdownMenuClasses.find((c) => hasClass(parentElement, c))
- || /* istanbul ignore next: fallback position */ dropdownString;
-
- /** @type {Record<string, Record<string, any>>} */
- let dropdownMargin = {
- dropdown: [offset, 0, 0],
- dropup: [0, 0, offset],
- dropstart: RTL ? [-1, 0, 0, offset] : [-1, offset, 0],
- dropend: RTL ? [-1, offset, 0] : [-1, 0, 0, offset],
- };
-
- /** @type {Record<string, Record<string, any>>} */
- const dropdownPosition = {
- dropdown: { top: '100%' },
- dropup: { top: 'auto', bottom: '100%' },
- dropstart: RTL ? { left: '100%', right: 'auto' } : { left: 'auto', right: '100%' },
- dropend: RTL ? { left: 'auto', right: '100%' } : { left: '100%', right: 'auto' },
- menuStart: RTL ? { right: 0, left: 'auto' } : { right: 'auto', left: 0 },
- menuEnd: RTL ? { right: 'auto', left: 0 } : { right: 0, left: 'auto' },
- };
-
- const { offsetWidth: menuWidth, offsetHeight: menuHeight } = menu;
-
- const { clientWidth, clientHeight } = getDocumentElement(element);
- const {
- left: targetLeft, top: targetTop,
- width: targetWidth, height: targetHeight,
- } = getBoundingClientRect(element);
-
- // dropstart | dropend
- const leftFullExceed = targetLeft - menuWidth - offset < 0;
- // dropend
- const rightFullExceed = targetLeft + menuWidth + targetWidth + offset >= clientWidth;
- // dropstart | dropend
- const bottomExceed = targetTop + menuHeight + offset >= clientHeight;
- // dropdown
- const bottomFullExceed = targetTop + menuHeight + targetHeight + offset >= clientHeight;
- // dropup
- const topExceed = targetTop - menuHeight - offset < 0;
- // dropdown / dropup
- const leftExceed = ((!RTL && menuEnd) || (RTL && !menuEnd))
- && targetLeft + targetWidth - menuWidth < 0;
- const rightExceed = ((RTL && menuEnd) || (!RTL && !menuEnd))
- && targetLeft + menuWidth >= clientWidth;
-
- // recompute position
- // handle RTL as well
- if (horizontalClass.includes(positionClass) && leftFullExceed && rightFullExceed) {
- positionClass = dropdownString;
- }
- if (positionClass === dropstartString && (!RTL ? leftFullExceed : rightFullExceed)) {
- positionClass = dropendString;
- }
- if (positionClass === dropendString && (RTL ? leftFullExceed : rightFullExceed)) {
- positionClass = dropstartString;
- }
- if (positionClass === dropupString && topExceed && !bottomFullExceed) {
- positionClass = dropdownString;
- }
- if (positionClass === dropdownString && bottomFullExceed && !topExceed) {
- positionClass = dropupString;
- }
-
- // override position for horizontal classes
- if (horizontalClass.includes(positionClass) && bottomExceed) {
- ObjectAssign(dropdownPosition[positionClass], {
- top: 'auto', bottom: 0,
- });
- }
-
- // override position for vertical classes
- if (verticalClass.includes(positionClass) && (leftExceed || rightExceed)) {
- // don't realign when menu is wider than window
- // in both RTL and non-RTL readability is KING
- let posAjust;
- if (!leftExceed && rightExceed && !RTL) posAjust = { left: 'auto', right: 0 };
- if (leftExceed && !rightExceed && RTL) posAjust = { left: 0, right: 'auto' };
- if (posAjust) ObjectAssign(dropdownPosition[positionClass], posAjust);
- }
-
- dropdownMargin = dropdownMargin[positionClass];
- setElementStyle(menu, {
- ...dropdownPosition[positionClass],
- margin: `${dropdownMargin.map((x) => (x ? `${x}px` : x)).join(' ')}`,
- });
-
- // override dropdown-menu-start | dropdown-menu-end
- if (verticalClass.includes(positionClass) && menuEnd) {
- /* istanbul ignore else */
- if (menuEnd) {
- const endAdjust = (!RTL && leftExceed) || (RTL && rightExceed)
- ? 'menuStart' : /* istanbul ignore next */'menuEnd';
- setElementStyle(menu, dropdownPosition[endAdjust]);
- }
- }
- }
-
- /**
- * Returns an `Array` of focusable items in the given dropdown-menu.
- * @param {HTMLElement} menu
- * @returns {HTMLElement[]}
- */
- function getMenuItems(menu) {
- return [...menu.children].map((c) => {
- if (c && menuFocusTags.includes(c.tagName)) return c;
- const { firstElementChild } = c;
- if (firstElementChild && menuFocusTags.includes(firstElementChild.tagName)) {
- return firstElementChild;
- }
- return null;
- }).filter((c) => c);
- }
-
- /**
- * Toggles on/off the listeners for the events that close the dropdown
- * as well as event that request a new position for the dropdown.
- *
- * @param {Dropdown} self the `Dropdown` instance
- */
- function toggleDropdownDismiss(self) {
- const { element, options } = self;
- const action = self.open ? addListener : removeListener;
- const doc = getDocument(element);
-
- action(doc, mouseclickEvent, dropdownDismissHandler);
- action(doc, focusEvent, dropdownDismissHandler);
- action(doc, keydownEvent, dropdownPreventScroll);
- action(doc, keyupEvent, dropdownKeyHandler);
-
- /* istanbul ignore else */
- if (options.display === 'dynamic') {
- [scrollEvent, resizeEvent].forEach((ev) => {
- action(getWindow(element), ev, dropdownLayoutHandler, passiveHandler);
- });
- }
- }
-
- /**
- * Toggles on/off the `click` event listener of the `Dropdown`.
- *
- * @param {Dropdown} self the `Dropdown` instance
- * @param {boolean=} add when `true`, it will add the event listener
- */
- function toggleDropdownHandler(self, add) {
- const action = add ? addListener : removeListener;
- action(self.element, mouseclickEvent, dropdownClickHandler);
- }
-
- /**
- * Returns the currently open `.dropdown` element.
- *
- * @param {(Node | Window)=} element target
- * @returns {HTMLElement?} the query result
- */
- function getCurrentOpenDropdown(element) {
- const currentParent = [...dropdownMenuClasses, 'btn-group', 'input-group']
- .map((c) => getElementsByClassName(`${c} ${showClass}`, getDocument(element)))
- .find((x) => x.length);
-
- if (currentParent && currentParent.length) {
- return [...currentParent[0].children]
- .find((x) => hasAttribute(x, dataBsToggle));
- }
- return null;
- }
-
- // DROPDOWN EVENT HANDLERS
- // =======================
- /**
- * Handles the `click` event for the `Dropdown` instance.
- *
- * @param {MouseEvent} e event object
- * @this {Document}
- */
- function dropdownDismissHandler(e) {
- const { target, type } = e;
-
- /* istanbul ignore next: impossible to satisfy */
- if (!target || !target.closest) return; // some weird FF bug #409
-
- const element = getCurrentOpenDropdown(target);
- const self = getDropdownInstance(element);
-
- /* istanbul ignore next */
- if (!self) return;
-
- const { parentElement, menu } = self;
-
- const hasData = closest(target, dropdownSelector) !== null;
- const isForm = parentElement && parentElement.contains(target)
- && (target.tagName === 'form' || closest(target, 'form') !== null);
-
- if (type === mouseclickEvent && isEmptyAnchor(target)) {
- e.preventDefault();
- }
- if (type === focusEvent
- && (target === element || target === menu || menu.contains(target))) {
- return;
- }
-
- /* istanbul ignore else */
- if (isForm || hasData) ; else if (self) {
- self.hide();
- }
- }
-
- /**
- * Handles `click` event listener for `Dropdown`.
- * @this {HTMLElement}
- * @param {MouseEvent} e event object
- */
- function dropdownClickHandler(e) {
- const element = this;
- const { target } = e;
- const self = getDropdownInstance(element);
-
- /* istanbul ignore else */
- if (self) {
- self.toggle();
- /* istanbul ignore else */
- if (target && isEmptyAnchor(target)) e.preventDefault();
- }
- }
-
- /**
- * Prevents scroll when dropdown-menu is visible.
- * @param {KeyboardEvent} e event object
- */
- function dropdownPreventScroll(e) {
- /* istanbul ignore else */
- if ([keyArrowDown, keyArrowUp].includes(e.code)) e.preventDefault();
- }
-
- /**
- * Handles keyboard `keydown` events for `Dropdown`.
- * @param {KeyboardEvent} e keyboard key
- * @this {Document}
- */
- function dropdownKeyHandler(e) {
- const { code } = e;
- const element = getCurrentOpenDropdown(this);
- const self = element && getDropdownInstance(element);
- const { activeElement } = element && getDocument(element);
- /* istanbul ignore next: impossible to satisfy */
- if (!self || !activeElement) return;
- const { menu, open } = self;
- const menuItems = getMenuItems(menu);
-
- // arrow up & down
- if (menuItems && menuItems.length && [keyArrowDown, keyArrowUp].includes(code)) {
- let idx = menuItems.indexOf(activeElement);
- /* istanbul ignore else */
- if (activeElement === element) {
- idx = 0;
- } else if (code === keyArrowUp) {
- idx = idx > 1 ? idx - 1 : 0;
- } else if (code === keyArrowDown) {
- idx = idx < menuItems.length - 1 ? idx + 1 : idx;
- }
- /* istanbul ignore else */
- if (menuItems[idx]) focus(menuItems[idx]);
- }
-
- if (keyEscape === code && open) {
- self.toggle();
- focus(element);
- }
- }
-
- /**
- * @this {globalThis}
- * @returns {void}
- */
- function dropdownLayoutHandler() {
- const element = getCurrentOpenDropdown(this);
- const self = element && getDropdownInstance(element);
-
- /* istanbul ignore else */
- if (self && self.open) styleDropdown(self);
- }
-
- // DROPDOWN DEFINITION
- // ===================
- /** Returns a new Dropdown instance. */
- class Dropdown extends BaseComponent {
- /**
- * @param {HTMLElement | string} target Element or string selector
- * @param {BSN.Options.Dropdown=} config the instance options
- */
- constructor(target, config) {
- super(target, config);
- // bind
- const self = this;
-
- // initialization element
- const { element } = self;
- const { parentElement } = element;
-
- // set targets
- /** @type {(Element | HTMLElement)} */
- self.parentElement = parentElement;
- /** @type {(Element | HTMLElement)} */
- self.menu = querySelector(`.${dropdownMenuClass}`, parentElement);
-
- // set initial state to closed
- /** @type {boolean} */
- self.open = false;
-
- // add event listener
- toggleDropdownHandler(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return dropdownComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return dropdownDefaults; }
- /* eslint-enable */
-
- // DROPDOWN PUBLIC METHODS
- // =======================
- /** Shows/hides the dropdown menu to the user. */
- toggle() {
- const self = this;
-
- if (self.open) self.hide();
- else self.show();
- }
-
- /** Shows the dropdown menu to the user. */
- show() {
- const self = this;
- const {
- element, open, menu, parentElement,
- } = self;
-
- /* istanbul ignore next */
- if (open) return;
-
- const currentElement = getCurrentOpenDropdown(element);
- const currentInstance = currentElement && getDropdownInstance(currentElement);
- if (currentInstance) currentInstance.hide();
-
- // dispatch event
- [showDropdownEvent, shownDropdownEvent].forEach((e) => {
- e.relatedTarget = element;
- });
- dispatchEvent(parentElement, showDropdownEvent);
- if (showDropdownEvent.defaultPrevented) return;
-
- addClass(menu, showClass);
- addClass(parentElement, showClass);
- setAttribute(element, ariaExpanded, 'true');
-
- // change menu position
- styleDropdown(self);
-
- self.open = !open;
-
- focus(element); // focus the element
- toggleDropdownDismiss(self);
- dispatchEvent(parentElement, shownDropdownEvent);
- }
-
- /** Hides the dropdown menu from the user. */
- hide() {
- const self = this;
- const {
- element, open, menu, parentElement,
- } = self;
-
- /* istanbul ignore next */
- if (!open) return;
-
- [hideDropdownEvent, hiddenDropdownEvent].forEach((e) => {
- e.relatedTarget = element;
- });
- dispatchEvent(parentElement, hideDropdownEvent);
- if (hideDropdownEvent.defaultPrevented) return;
-
- removeClass(menu, showClass);
- removeClass(parentElement, showClass);
- setAttribute(element, ariaExpanded, 'false');
-
- self.open = !open;
- // only re-attach handler if the instance is not disposed
- toggleDropdownDismiss(self);
- dispatchEvent(parentElement, hiddenDropdownEvent);
- }
-
- /** Removes the `Dropdown` component from the target element. */
- dispose() {
- const self = this;
- if (self.open) self.hide();
-
- toggleDropdownHandler(self);
-
- super.dispose();
- }
- }
-
- ObjectAssign(Dropdown, {
- selector: dropdownSelector,
- init: dropdownInitCallback,
- getInstance: getDropdownInstance,
- });
-
- /**
- * A global namespace for aria-hidden.
- * @type {string}
- */
- const ariaHidden = 'aria-hidden';
-
- /**
- * A global namespace for aria-modal.
- * @type {string}
- */
- const ariaModal = 'aria-modal';
-
- /**
- * Shortcut for `HTMLElement.removeAttribute()` method.
- * @param {HTMLElement} element target element
- * @param {string} attribute attribute name
- * @returns {void}
- */
- const removeAttribute = (element, attribute) => element.removeAttribute(attribute);
-
- /**
- * Returns the `document.body` or the `<body>` element.
- *
- * @param {(Node | Window)=} node
- * @returns {HTMLBodyElement}
- */
- function getDocumentBody(node) {
- return getDocument(node).body;
- }
-
- /** @type {string} */
- const modalString = 'modal';
-
- /** @type {string} */
- const modalComponent = 'Modal';
-
- /**
- * Check if target is a `ShadowRoot`.
- *
- * @param {any} element target
- * @returns {boolean} the query result
- */
- const isShadowRoot = (element) => (element && element.constructor.name === 'ShadowRoot')
- || false;
-
- /**
- * Returns the `parentNode` also going through `ShadowRoot`.
- * @see https://github.com/floating-ui/floating-ui
- *
- * @param {Node} node the target node
- * @returns {Node} the apropriate parent node
- */
- function getParentNode(node) {
- if (node.nodeName === 'HTML') {
- return node;
- }
-
- // this is a quicker (but less type safe) way to save quite some bytes from the bundle
- return (
- node.assignedSlot // step into the shadow DOM of the parent of a slotted node
- || node.parentNode // DOM Element detected
- || (isShadowRoot(node) && node.host) // ShadowRoot detected
- || getDocumentElement(node) // fallback
- );
- }
-
- /**
- * Check if a target element is a `<table>`, `<td>` or `<th>`.
- * This specific check is important for determining
- * the `offsetParent` of a given element.
- *
- * @param {any} element the target element
- * @returns {boolean} the query result
- */
- const isTableElement = (element) => (element && ['TABLE', 'TD', 'TH'].includes(element.tagName))
- || false;
-
- /**
- * Returns an `HTMLElement` to be used as default value for *options.container*
- * for `Tooltip` / `Popover` components.
- *
- * When `getOffset` is *true*, it returns the `offsetParent` for tooltip/popover
- * offsets computation similar to **floating-ui**.
- * @see https://github.com/floating-ui/floating-ui
- *
- * @param {HTMLElement} element the target
- * @param {boolean=} getOffset when *true* it will return an `offsetParent`
- * @returns {ParentNode | Window} the query result
- */
- function getElementContainer(element, getOffset) {
- const majorBlockTags = ['HTML', 'BODY'];
-
- if (getOffset) {
- /** @type {any} */
- let { offsetParent } = element;
- const win = getWindow(element);
-
- while (offsetParent && (isTableElement(offsetParent)
- || (isHTMLElement(offsetParent)
- // we must count for both fixed & sticky
- && !['sticky', 'fixed'].includes(getElementStyle(offsetParent, 'position'))))) {
- offsetParent = offsetParent.offsetParent;
- }
-
- if (!offsetParent || (majorBlockTags.includes(offsetParent.tagName)
- || getElementStyle(offsetParent, 'position') === 'static')) {
- offsetParent = win;
- }
- return offsetParent;
- }
-
- /** @type {ParentNode[]} */
- const containers = [];
- /** @type {ParentNode} */
- let { parentNode } = element;
-
- while (parentNode && !majorBlockTags.includes(parentNode.nodeName)) {
- parentNode = getParentNode(parentNode);
- /* istanbul ignore else */
- if (!(isShadowRoot(parentNode) || !!parentNode.shadowRoot
- || isTableElement(parentNode))) {
- containers.push(parentNode);
- }
- }
-
- return containers.find((c, i) => {
- if (getElementStyle(c, 'position') !== 'relative'
- && containers.slice(i + 1).every((r) => getElementStyle(r, 'position') === 'static')) {
- return c;
- }
- return null;
- }) || getDocumentBody(element);
- }
-
- /**
- * Global namespace for components `fixed-top` class.
- */
- const fixedTopClass = 'fixed-top';
-
- /**
- * Global namespace for components `fixed-bottom` class.
- */
- const fixedBottomClass = 'fixed-bottom';
-
- /**
- * Global namespace for components `sticky-top` class.
- */
- const stickyTopClass = 'sticky-top';
-
- /**
- * Global namespace for components `position-sticky` class.
- */
- const positionStickyClass = 'position-sticky';
-
- /** @param {(HTMLElement | Document)=} parent */
- const getFixedItems = (parent) => [
- ...getElementsByClassName(fixedTopClass, parent),
- ...getElementsByClassName(fixedBottomClass, parent),
- ...getElementsByClassName(stickyTopClass, parent),
- ...getElementsByClassName(positionStickyClass, parent),
- ...getElementsByClassName('is-fixed', parent),
- ];
-
- /**
- * Removes *padding* and *overflow* from the `<body>`
- * and all spacing from fixed items.
- * @param {HTMLElement=} element the target modal/offcanvas
- */
- function resetScrollbar(element) {
- const bd = getDocumentBody(element);
- setElementStyle(bd, {
- paddingRight: '',
- overflow: '',
- });
-
- const fixedItems = getFixedItems(bd);
-
- if (fixedItems.length) {
- fixedItems.forEach((fixed) => {
- setElementStyle(fixed, {
- paddingRight: '',
- marginRight: '',
- });
- });
- }
- }
-
- /**
- * Returns the scrollbar width if the body does overflow
- * the window.
- * @param {HTMLElement=} element
- * @returns {number} the value
- */
- function measureScrollbar(element) {
- const { clientWidth } = getDocumentElement(element);
- const { innerWidth } = getWindow(element);
- return Math.abs(innerWidth - clientWidth);
- }
-
- /**
- * Sets the `<body>` and fixed items style when modal / offcanvas
- * is shown to the user.
- *
- * @param {HTMLElement} element the target modal/offcanvas
- * @param {boolean=} overflow body does overflow or not
- */
- function setScrollbar(element, overflow) {
- const bd = getDocumentBody(element);
- const bodyPad = parseInt(getElementStyle(bd, 'paddingRight'), 10);
- const isOpen = getElementStyle(bd, 'overflow') === 'hidden';
- const sbWidth = isOpen && bodyPad ? 0 : measureScrollbar(element);
- const fixedItems = getFixedItems(bd);
-
- /* istanbul ignore else */
- if (overflow) {
- setElementStyle(bd, {
- overflow: 'hidden',
- paddingRight: `${bodyPad + sbWidth}px`,
- });
-
- /* istanbul ignore else */
- if (fixedItems.length) {
- fixedItems.forEach((fixed) => {
- const itemPadValue = getElementStyle(fixed, 'paddingRight');
- fixed.style.paddingRight = `${parseInt(itemPadValue, 10) + sbWidth}px`;
- /* istanbul ignore else */
- if ([stickyTopClass, positionStickyClass].some((c) => hasClass(fixed, c))) {
- const itemMValue = getElementStyle(fixed, 'marginRight');
- fixed.style.marginRight = `${parseInt(itemMValue, 10) - sbWidth}px`;
- }
- });
- }
- }
- }
-
- /**
- * This is a shortie for `document.createElement` method
- * which allows you to create a new `HTMLElement` for a given `tagName`
- * or based on an object with specific non-readonly attributes:
- * `id`, `className`, `textContent`, `style`, etc.
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
- *
- * @param {Record<string, string> | string} param `tagName` or object
- * @return {HTMLElement} a new `HTMLElement` or `Element`
- */
- function createElement(param) {
- if (!param) return null;
-
- if (typeof param === 'string') {
- return getDocument().createElement(param);
- }
-
- const { tagName } = param;
- const attr = { ...param };
- const newElement = createElement(tagName);
- delete attr.tagName;
- ObjectAssign(newElement, attr);
- return newElement;
- }
-
- /** @type {string} */
- const offcanvasString = 'offcanvas';
-
- const backdropString = 'backdrop';
- const modalBackdropClass = `${modalString}-${backdropString}`;
- const offcanvasBackdropClass = `${offcanvasString}-${backdropString}`;
- const modalActiveSelector = `.${modalString}.${showClass}`;
- const offcanvasActiveSelector = `.${offcanvasString}.${showClass}`;
-
- // any document would suffice
- const overlay = createElement('div');
-
- /**
- * Returns the current active modal / offcancas element.
- * @param {HTMLElement=} element the context element
- * @returns {HTMLElement?} the requested element
- */
- function getCurrentOpen(element) {
- return querySelector(`${modalActiveSelector},${offcanvasActiveSelector}`, getDocument(element));
- }
-
- /**
- * Toogles from a Modal overlay to an Offcanvas, or vice-versa.
- * @param {boolean=} isModal
- */
- function toggleOverlayType(isModal) {
- const targetClass = isModal ? modalBackdropClass : offcanvasBackdropClass;
- [modalBackdropClass, offcanvasBackdropClass].forEach((c) => {
- removeClass(overlay, c);
- });
- addClass(overlay, targetClass);
- }
-
- /**
- * Append the overlay to DOM.
- * @param {HTMLElement} container
- * @param {boolean} hasFade
- * @param {boolean=} isModal
- */
- function appendOverlay(container, hasFade, isModal) {
- toggleOverlayType(isModal);
- container.append(overlay);
- if (hasFade) addClass(overlay, fadeClass);
- }
-
- /**
- * Shows the overlay to the user.
- */
- function showOverlay() {
- if (!hasClass(overlay, showClass)) {
- addClass(overlay, showClass);
- reflow(overlay);
- }
- }
-
- /**
- * Hides the overlay from the user.
- */
- function hideOverlay() {
- removeClass(overlay, showClass);
- }
-
- /**
- * Removes the overlay from DOM.
- * @param {HTMLElement=} element
- */
- function removeOverlay(element) {
- if (!getCurrentOpen(element)) {
- removeClass(overlay, fadeClass);
- overlay.remove();
- resetScrollbar(element);
- }
- }
-
- /**
- * @param {HTMLElement} element target
- * @returns {boolean}
- */
- function isVisible(element) {
- return isHTMLElement(element)
- && getElementStyle(element, 'visibility') !== 'hidden'
- && element.offsetParent !== null;
- }
-
- /* Native JavaScript for Bootstrap 5 | Modal
- -------------------------------------------- */
-
- // MODAL PRIVATE GC
- // ================
- const modalSelector = `.${modalString}`;
- const modalToggleSelector = `[${dataBsToggle}="${modalString}"]`;
- const modalDismissSelector = `[${dataBsDismiss}="${modalString}"]`;
- const modalStaticClass = `${modalString}-static`;
-
- const modalDefaults = {
- backdrop: true, // boolean|string
- keyboard: true, // boolean
- };
-
- /**
- * Static method which returns an existing `Modal` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Modal>}
- */
- const getModalInstance = (element) => getInstance(element, modalComponent);
-
- /**
- * A `Modal` initialization callback.
- * @type {BSN.InitCallback<Modal>}
- */
- const modalInitCallback = (element) => new Modal(element);
-
- // MODAL CUSTOM EVENTS
- // ===================
- const showModalEvent = OriginalEvent(`show.bs.${modalString}`);
- const shownModalEvent = OriginalEvent(`shown.bs.${modalString}`);
- const hideModalEvent = OriginalEvent(`hide.bs.${modalString}`);
- const hiddenModalEvent = OriginalEvent(`hidden.bs.${modalString}`);
-
- // MODAL PRIVATE METHODS
- // =====================
- /**
- * Applies special style for the `<body>` and fixed elements
- * when a modal instance is shown to the user.
- *
- * @param {Modal} self the `Modal` instance
- */
- function setModalScrollbar(self) {
- const { element } = self;
- const scrollbarWidth = measureScrollbar(element);
- const { clientHeight, scrollHeight } = getDocumentElement(element);
- const { clientHeight: modalHeight, scrollHeight: modalScrollHeight } = element;
- const modalOverflow = modalHeight !== modalScrollHeight;
-
- /* istanbul ignore else */
- if (!modalOverflow && scrollbarWidth) {
- const pad = !isRTL(element) ? 'paddingRight' : /* istanbul ignore next */'paddingLeft';
- const padStyle = {};
- padStyle[pad] = `${scrollbarWidth}px`;
- setElementStyle(element, padStyle);
- }
- setScrollbar(element, (modalOverflow || clientHeight !== scrollHeight));
- }
-
- /**
- * Toggles on/off the listeners of events that close the modal.
- *
- * @param {Modal} self the `Modal` instance
- * @param {boolean=} add when `true`, event listeners are added
- */
- function toggleModalDismiss(self, add) {
- const action = add ? addListener : removeListener;
- const { element } = self;
- action(element, mouseclickEvent, modalDismissHandler);
- action(getWindow(element), resizeEvent, self.update, passiveHandler);
- action(getDocument(element), keydownEvent, modalKeyHandler);
- }
-
- /**
- * Toggles on/off the `click` event listener of the `Modal` instance.
- * @param {Modal} self the `Modal` instance
- * @param {boolean=} add when `true`, event listener is added
- */
- function toggleModalHandler(self, add) {
- const action = add ? addListener : removeListener;
- const { triggers } = self;
-
- /* istanbul ignore else */
- if (triggers.length) {
- triggers.forEach((btn) => action(btn, mouseclickEvent, modalClickHandler));
- }
- }
-
- /**
- * Executes after a modal is hidden to the user.
- * @param {Modal} self the `Modal` instance
- * @param {Function} callback the `Modal` instance
- */
- function afterModalHide(self, callback) {
- const { triggers, element, relatedTarget } = self;
- removeOverlay(element);
- setElementStyle(element, { paddingRight: '', display: '' });
- toggleModalDismiss(self);
-
- const focusElement = showModalEvent.relatedTarget || triggers.find(isVisible);
- /* istanbul ignore else */
- if (focusElement) focus(focusElement);
-
- /* istanbul ignore else */
- if (callback) callback();
-
- hiddenModalEvent.relatedTarget = relatedTarget;
- dispatchEvent(element, hiddenModalEvent);
- }
-
- /**
- * Executes after a modal is shown to the user.
- * @param {Modal} self the `Modal` instance
- */
- function afterModalShow(self) {
- const { element, relatedTarget } = self;
- focus(element);
- toggleModalDismiss(self, true);
-
- shownModalEvent.relatedTarget = relatedTarget;
- dispatchEvent(element, shownModalEvent);
- }
-
- /**
- * Executes before a modal is shown to the user.
- * @param {Modal} self the `Modal` instance
- */
- function beforeModalShow(self) {
- const { element, hasFade } = self;
- setElementStyle(element, { display: 'block' });
-
- setModalScrollbar(self);
- /* istanbul ignore else */
- if (!getCurrentOpen(element)) {
- setElementStyle(getDocumentBody(element), { overflow: 'hidden' });
- }
-
- addClass(element, showClass);
- removeAttribute(element, ariaHidden);
- setAttribute(element, ariaModal, 'true');
-
- if (hasFade) emulateTransitionEnd(element, () => afterModalShow(self));
- else afterModalShow(self);
- }
-
- /**
- * Executes before a modal is hidden to the user.
- * @param {Modal} self the `Modal` instance
- * @param {Function=} callback when `true` skip animation
- */
- function beforeModalHide(self, callback) {
- const {
- element, options, hasFade,
- } = self;
-
- // callback can also be the transitionEvent object, we wanna make sure it's not
- // call is not forced and overlay is visible
- if (options.backdrop && !callback && hasFade && hasClass(overlay, showClass)
- && !getCurrentOpen(element)) { // AND no modal is visible
- hideOverlay();
- emulateTransitionEnd(overlay, () => afterModalHide(self));
- } else {
- afterModalHide(self, callback);
- }
- }
-
- // MODAL EVENT HANDLERS
- // ====================
- /**
- * Handles the `click` event listener for modal.
- * @param {MouseEvent} e the `Event` object
- */
- function modalClickHandler(e) {
- const { target } = e;
-
- const trigger = target && closest(target, modalToggleSelector);
- const element = trigger && getTargetElement(trigger);
- const self = element && getModalInstance(element);
-
- /* istanbul ignore else */
- if (trigger && trigger.tagName === 'A') e.preventDefault();
- self.relatedTarget = trigger;
- self.toggle();
- }
-
- /**
- * Handles the `keydown` event listener for modal
- * to hide the modal when user type the `ESC` key.
- *
- * @param {KeyboardEvent} e the `Event` object
- */
- function modalKeyHandler({ code, target }) {
- const element = querySelector(modalActiveSelector, getDocument(target));
- const self = element && getModalInstance(element);
-
- const { options } = self;
- /* istanbul ignore else */
- if (options.keyboard && code === keyEscape // the keyboard option is enabled and the key is 27
- && hasClass(element, showClass)) { // the modal is not visible
- self.relatedTarget = null;
- self.hide();
- }
- }
-
- /**
- * Handles the `click` event listeners that hide the modal.
- *
- * @this {HTMLElement}
- * @param {MouseEvent} e the `Event` object
- */
- function modalDismissHandler(e) {
- const element = this;
- const self = getModalInstance(element);
-
- // this timer is needed
- /* istanbul ignore next: must have a filter */
- if (!self || Timer.get(element)) return;
-
- const { options, isStatic, modalDialog } = self;
- const { backdrop } = options;
- const { target } = e;
-
- const selectedText = getDocument(element).getSelection().toString().length;
- const targetInsideDialog = modalDialog.contains(target);
- const dismiss = target && closest(target, modalDismissSelector);
-
- /* istanbul ignore else */
- if (isStatic && !targetInsideDialog) {
- Timer.set(element, () => {
- addClass(element, modalStaticClass);
- emulateTransitionEnd(modalDialog, () => staticTransitionEnd(self));
- }, 17);
- } else if (dismiss || (!selectedText && !isStatic && !targetInsideDialog && backdrop)) {
- self.relatedTarget = dismiss || null;
- self.hide();
- e.preventDefault();
- }
- }
-
- /**
- * Handles the `transitionend` event listeners for `Modal`.
- *
- * @param {Modal} self the `Modal` instance
- */
- function staticTransitionEnd(self) {
- const { element, modalDialog } = self;
- const duration = getElementTransitionDuration(modalDialog) + 17;
- removeClass(element, modalStaticClass);
- // user must wait for zoom out transition
- Timer.set(element, () => Timer.clear(element), duration);
- }
-
- // MODAL DEFINITION
- // ================
- /** Returns a new `Modal` instance. */
- class Modal extends BaseComponent {
- /**
- * @param {HTMLElement | string} target usually the `.modal` element
- * @param {BSN.Options.Modal=} config instance options
- */
- constructor(target, config) {
- super(target, config);
-
- // bind
- const self = this;
-
- // the modal
- const { element } = self;
-
- // the modal-dialog
- /** @type {(HTMLElement)} */
- self.modalDialog = querySelector(`.${modalString}-dialog`, element);
-
- // modal can have multiple triggering elements
- /** @type {HTMLElement[]} */
- self.triggers = [...querySelectorAll(modalToggleSelector, getDocument(element))]
- .filter((btn) => getTargetElement(btn) === element);
-
- // additional internals
- /** @type {boolean} */
- self.isStatic = self.options.backdrop === 'static';
- /** @type {boolean} */
- self.hasFade = hasClass(element, fadeClass);
- /** @type {HTMLElement?} */
- self.relatedTarget = null;
- /** @type {HTMLBodyElement | HTMLElement} */
- self.container = getElementContainer(element);
-
- // attach event listeners
- toggleModalHandler(self, true);
-
- // bind
- self.update = self.update.bind(self);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return modalComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return modalDefaults; }
- /* eslint-enable */
-
- // MODAL PUBLIC METHODS
- // ====================
- /** Toggles the visibility of the modal. */
- toggle() {
- const self = this;
- if (hasClass(self.element, showClass)) self.hide();
- else self.show();
- }
-
- /** Shows the modal to the user. */
- show() {
- const self = this;
- const {
- element, options, hasFade, relatedTarget, container,
- } = self;
- const { backdrop } = options;
- let overlayDelay = 0;
-
- if (hasClass(element, showClass)) return;
-
- showModalEvent.relatedTarget = relatedTarget || null;
- dispatchEvent(element, showModalEvent);
- if (showModalEvent.defaultPrevented) return;
-
- // we elegantly hide any opened modal/offcanvas
- const currentOpen = getCurrentOpen(element);
- if (currentOpen && currentOpen !== element) {
- const this1 = getModalInstance(currentOpen);
- const that1 = this1
- || /* istanbul ignore next */getInstance(currentOpen, 'Offcanvas');
- that1.hide();
- }
-
- if (backdrop) {
- if (!container.contains(overlay)) {
- appendOverlay(container, hasFade, true);
- } else {
- toggleOverlayType(true);
- }
-
- overlayDelay = getElementTransitionDuration(overlay);
-
- showOverlay();
- setTimeout(() => beforeModalShow(self), overlayDelay);
- } else {
- beforeModalShow(self);
- /* istanbul ignore else */
- if (currentOpen && hasClass(overlay, showClass)) {
- hideOverlay();
- }
- }
- }
-
- /**
- * Hide the modal from the user.
- * @param {Function=} callback when defined it will skip animation
- */
- hide(callback) {
- const self = this;
- const {
- element, hasFade, relatedTarget,
- } = self;
-
- if (!hasClass(element, showClass)) return;
-
- hideModalEvent.relatedTarget = relatedTarget || null;
- dispatchEvent(element, hideModalEvent);
- if (hideModalEvent.defaultPrevented) return;
- removeClass(element, showClass);
- setAttribute(element, ariaHidden, 'true');
- removeAttribute(element, ariaModal);
-
- // if (hasFade && callback) {
- /* istanbul ignore else */
- if (hasFade) {
- emulateTransitionEnd(element, () => beforeModalHide(self, callback));
- } else {
- beforeModalHide(self, callback);
- }
- }
-
- /**
- * Updates the modal layout.
- * @this {Modal} the modal instance
- */
- update() {
- const self = this;
- /* istanbul ignore else */
- if (hasClass(self.element, showClass)) setModalScrollbar(self);
- }
-
- /** Removes the `Modal` component from target element. */
- dispose() {
- const self = this;
- toggleModalHandler(self);
- // use callback
- self.hide(() => super.dispose());
- }
- }
-
- ObjectAssign(Modal, {
- selector: modalSelector,
- init: modalInitCallback,
- getInstance: getModalInstance,
- });
-
- /** @type {string} */
- const offcanvasComponent = 'Offcanvas';
-
- /* Native JavaScript for Bootstrap 5 | OffCanvas
- ------------------------------------------------ */
-
- // OFFCANVAS PRIVATE GC
- // ====================
- const offcanvasSelector = `.${offcanvasString}`;
- const offcanvasToggleSelector = `[${dataBsToggle}="${offcanvasString}"]`;
- const offcanvasDismissSelector = `[${dataBsDismiss}="${offcanvasString}"]`;
- const offcanvasTogglingClass = `${offcanvasString}-toggling`;
-
- const offcanvasDefaults = {
- backdrop: true, // boolean
- keyboard: true, // boolean
- scroll: false, // boolean
- };
-
- /**
- * Static method which returns an existing `Offcanvas` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Offcanvas>}
- */
- const getOffcanvasInstance = (element) => getInstance(element, offcanvasComponent);
-
- /**
- * An `Offcanvas` initialization callback.
- * @type {BSN.InitCallback<Offcanvas>}
- */
- const offcanvasInitCallback = (element) => new Offcanvas(element);
-
- // OFFCANVAS CUSTOM EVENTS
- // =======================
- const showOffcanvasEvent = OriginalEvent(`show.bs.${offcanvasString}`);
- const shownOffcanvasEvent = OriginalEvent(`shown.bs.${offcanvasString}`);
- const hideOffcanvasEvent = OriginalEvent(`hide.bs.${offcanvasString}`);
- const hiddenOffcanvasEvent = OriginalEvent(`hidden.bs.${offcanvasString}`);
-
- // OFFCANVAS PRIVATE METHODS
- // =========================
- /**
- * Sets additional style for the `<body>` and other elements
- * when showing an offcanvas to the user.
- *
- * @param {Offcanvas} self the `Offcanvas` instance
- */
- function setOffCanvasScrollbar(self) {
- const { element } = self;
- const { clientHeight, scrollHeight } = getDocumentElement(element);
- setScrollbar(element, clientHeight !== scrollHeight);
- }
-
- /**
- * Toggles on/off the `click` event listeners.
- *
- * @param {Offcanvas} self the `Offcanvas` instance
- * @param {boolean=} add when *true*, listeners are added
- */
- function toggleOffcanvasEvents(self, add) {
- const action = add ? addListener : removeListener;
- self.triggers.forEach((btn) => action(btn, mouseclickEvent, offcanvasTriggerHandler));
- }
-
- /**
- * Toggles on/off the listeners of the events that close the offcanvas.
- *
- * @param {Offcanvas} self the `Offcanvas` instance
- * @param {boolean=} add when *true* listeners are added
- */
- function toggleOffCanvasDismiss(self, add) {
- const action = add ? addListener : removeListener;
- const doc = getDocument(self.element);
- action(doc, keydownEvent, offcanvasKeyDismissHandler);
- action(doc, mouseclickEvent, offcanvasDismissHandler);
- }
-
- /**
- * Executes before showing the offcanvas.
- *
- * @param {Offcanvas} self the `Offcanvas` instance
- */
- function beforeOffcanvasShow(self) {
- const { element, options } = self;
-
- /* istanbul ignore else */
- if (!options.scroll) {
- setOffCanvasScrollbar(self);
- setElementStyle(getDocumentBody(element), { overflow: 'hidden' });
- }
-
- addClass(element, offcanvasTogglingClass);
- addClass(element, showClass);
- setElementStyle(element, { visibility: 'visible' });
-
- emulateTransitionEnd(element, () => showOffcanvasComplete(self));
- }
-
- /**
- * Executes before hiding the offcanvas.
- *
- * @param {Offcanvas} self the `Offcanvas` instance
- * @param {Function=} callback the hide callback
- */
- function beforeOffcanvasHide(self, callback) {
- const { element, options } = self;
- const currentOpen = getCurrentOpen(element);
-
- element.blur();
-
- if (!currentOpen && options.backdrop && hasClass(overlay, showClass)) {
- hideOverlay();
- emulateTransitionEnd(overlay, () => hideOffcanvasComplete(self, callback));
- } else hideOffcanvasComplete(self, callback);
- }
-
- // OFFCANVAS EVENT HANDLERS
- // ========================
- /**
- * Handles the `click` event listeners.
- *
- * @this {HTMLElement}
- * @param {MouseEvent} e the `Event` object
- */
- function offcanvasTriggerHandler(e) {
- const trigger = closest(this, offcanvasToggleSelector);
- const element = trigger && getTargetElement(trigger);
- const self = element && getOffcanvasInstance(element);
-
- /* istanbul ignore else */
- if (self) {
- self.relatedTarget = trigger;
- self.toggle();
- /* istanbul ignore else */
- if (trigger && trigger.tagName === 'A') {
- e.preventDefault();
- }
- }
- }
-
- /**
- * Handles the event listeners that close the offcanvas.
- *
- * @param {MouseEvent} e the `Event` object
- */
- function offcanvasDismissHandler(e) {
- const { target } = e;
- const element = querySelector(offcanvasActiveSelector, getDocument(target));
- const offCanvasDismiss = querySelector(offcanvasDismissSelector, element);
- const self = getOffcanvasInstance(element);
-
- /* istanbul ignore next: must have a filter */
- if (!self) return;
-
- const { options, triggers } = self;
- const { backdrop } = options;
- const trigger = closest(target, offcanvasToggleSelector);
- const selection = getDocument(element).getSelection();
-
- if (overlay.contains(target) && backdrop === 'static') return;
-
- /* istanbul ignore else */
- if (!(selection && selection.toString().length)
- && ((!element.contains(target) && backdrop
- && /* istanbul ignore next */(!trigger || triggers.includes(target)))
- || (offCanvasDismiss && offCanvasDismiss.contains(target)))) {
- self.relatedTarget = offCanvasDismiss && offCanvasDismiss.contains(target)
- ? offCanvasDismiss : null;
- self.hide();
- }
-
- /* istanbul ignore next */
- if (trigger && trigger.tagName === 'A') e.preventDefault();
- }
-
- /**
- * Handles the `keydown` event listener for offcanvas
- * to hide it when user type the `ESC` key.
- *
- * @param {KeyboardEvent} e the `Event` object
- */
- function offcanvasKeyDismissHandler({ code, target }) {
- const element = querySelector(offcanvasActiveSelector, getDocument(target));
-
- const self = getOffcanvasInstance(element);
-
- /* istanbul ignore next: must filter */
- if (!self) return;
-
- /* istanbul ignore else */
- if (self.options.keyboard && code === keyEscape) {
- self.relatedTarget = null;
- self.hide();
- }
- }
-
- /**
- * Handles the `transitionend` when showing the offcanvas.
- *
- * @param {Offcanvas} self the `Offcanvas` instance
- */
- function showOffcanvasComplete(self) {
- const { element } = self;
- removeClass(element, offcanvasTogglingClass);
-
- removeAttribute(element, ariaHidden);
- setAttribute(element, ariaModal, 'true');
- setAttribute(element, 'role', 'dialog');
-
- dispatchEvent(element, shownOffcanvasEvent);
-
- toggleOffCanvasDismiss(self, true);
- focus(element);
- }
-
- /**
- * Handles the `transitionend` when hiding the offcanvas.
- *
- * @param {Offcanvas} self the `Offcanvas` instance
- * @param {Function} callback the hide callback
- */
- function hideOffcanvasComplete(self, callback) {
- const { element, triggers } = self;
-
- setAttribute(element, ariaHidden, 'true');
- removeAttribute(element, ariaModal);
- removeAttribute(element, 'role');
- setElementStyle(element, { visibility: '' });
-
- const visibleTrigger = showOffcanvasEvent.relatedTarget || triggers.find((x) => isVisible(x));
- /* istanbul ignore else */
- if (visibleTrigger) focus(visibleTrigger);
-
- removeOverlay(element);
-
- dispatchEvent(element, hiddenOffcanvasEvent);
- removeClass(element, offcanvasTogglingClass);
-
- // must check for open instances
- if (!getCurrentOpen(element)) {
- toggleOffCanvasDismiss(self);
- }
- // callback
- if (callback) callback();
- }
-
- // OFFCANVAS DEFINITION
- // ====================
- /** Returns a new `Offcanvas` instance. */
- class Offcanvas extends BaseComponent {
- /**
- * @param {HTMLElement | string} target usually an `.offcanvas` element
- * @param {BSN.Options.Offcanvas=} config instance options
- */
- constructor(target, config) {
- super(target, config);
- const self = this;
-
- // instance element
- const { element } = self;
-
- // all the triggering buttons
- /** @type {HTMLElement[]} */
- self.triggers = [...querySelectorAll(offcanvasToggleSelector, getDocument(element))]
- .filter((btn) => getTargetElement(btn) === element);
-
- // additional instance property
- /** @type {HTMLBodyElement | HTMLElement} */
- self.container = getElementContainer(element);
- /** @type {HTMLElement?} */
- self.relatedTarget = null;
-
- // attach event listeners
- toggleOffcanvasEvents(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return offcanvasComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return offcanvasDefaults; }
- /* eslint-enable */
-
- // OFFCANVAS PUBLIC METHODS
- // ========================
- /** Shows or hides the offcanvas from the user. */
- toggle() {
- const self = this;
- if (hasClass(self.element, showClass)) self.hide();
- else self.show();
- }
-
- /** Shows the offcanvas to the user. */
- show() {
- const self = this;
- const {
- element, options, container, relatedTarget,
- } = self;
- let overlayDelay = 0;
-
- if (hasClass(element, showClass)) return;
-
- showOffcanvasEvent.relatedTarget = relatedTarget;
- shownOffcanvasEvent.relatedTarget = relatedTarget;
- dispatchEvent(element, showOffcanvasEvent);
- if (showOffcanvasEvent.defaultPrevented) return;
-
- // we elegantly hide any opened modal/offcanvas
- const currentOpen = getCurrentOpen(element);
- if (currentOpen && currentOpen !== element) {
- const this1 = getOffcanvasInstance(currentOpen);
- const that1 = this1
- || /* istanbul ignore next */getInstance(currentOpen, 'Modal');
- that1.hide();
- }
-
- if (options.backdrop) {
- if (!container.contains(overlay)) {
- appendOverlay(container, true);
- } else {
- toggleOverlayType();
- }
-
- overlayDelay = getElementTransitionDuration(overlay);
- showOverlay();
-
- setTimeout(() => beforeOffcanvasShow(self), overlayDelay);
- } else {
- beforeOffcanvasShow(self);
- /* istanbul ignore else */
- if (currentOpen && hasClass(overlay, showClass)) {
- hideOverlay();
- }
- }
- }
-
- /**
- * Hides the offcanvas from the user.
- * @param {Function=} callback when `true` it will skip animation
- */
- hide(callback) {
- const self = this;
- const { element, relatedTarget } = self;
-
- if (!hasClass(element, showClass)) return;
-
- hideOffcanvasEvent.relatedTarget = relatedTarget;
- hiddenOffcanvasEvent.relatedTarget = relatedTarget;
- dispatchEvent(element, hideOffcanvasEvent);
- if (hideOffcanvasEvent.defaultPrevented) return;
-
- addClass(element, offcanvasTogglingClass);
- removeClass(element, showClass);
-
- if (!callback) {
- emulateTransitionEnd(element, () => beforeOffcanvasHide(self, callback));
- } else beforeOffcanvasHide(self, callback);
- }
-
- /** Removes the `Offcanvas` from the target element. */
- dispose() {
- const self = this;
- toggleOffcanvasEvents(self);
- self.hide(() => super.dispose());
- }
- }
-
- ObjectAssign(Offcanvas, {
- selector: offcanvasSelector,
- init: offcanvasInitCallback,
- getInstance: getOffcanvasInstance,
- });
-
- /** @type {string} */
- const popoverString = 'popover';
-
- /** @type {string} */
- const popoverComponent = 'Popover';
-
- /** @type {string} */
- const tooltipString = 'tooltip';
-
- /**
- * Returns a template for Popover / Tooltip.
- *
- * @param {string} tipType the expected markup type
- * @returns {string} the template markup
- */
- function getTipTemplate(tipType) {
- const isTooltip = tipType === tooltipString;
- const bodyClass = isTooltip ? `${tipType}-inner` : `${tipType}-body`;
- const header = !isTooltip ? `<h3 class="${tipType}-header"></h3>` : '';
- const arrow = `<div class="${tipType}-arrow"></div>`;
- const body = `<div class="${bodyClass}"></div>`;
- return `<div class="${tipType}" role="${tooltipString}">${header + arrow + body}</div>`;
- }
-
- /**
- * Checks if an element is an `<svg>` (or any type of SVG element),
- * `<img>` or `<video>`.
- *
- * *Tooltip* / *Popover* works different with media elements.
- * @param {any} element the target element
- * @returns {boolean} the query result
- */
-
- const isMedia = (element) => (
- element
- && element.nodeType === 1
- && ['SVG', 'Image', 'Video'].some((s) => element.constructor.name.includes(s))) || false;
-
- /**
- * Returns an `{x,y}` object with the target
- * `HTMLElement` / `Node` scroll position.
- *
- * @see https://github.com/floating-ui/floating-ui
- *
- * @param {HTMLElement | Window} element target node / element
- * @returns {{x: number, y: number}} the scroll tuple
- */
- function getNodeScroll(element) {
- const isWin = 'scrollX' in element;
- const x = isWin ? element.scrollX : element.scrollLeft;
- const y = isWin ? element.scrollY : element.scrollTop;
-
- return { x, y };
- }
-
- /**
- * Checks if a target `HTMLElement` is affected by scale.
- * @see https://github.com/floating-ui/floating-ui
- *
- * @param {HTMLElement} element target
- * @returns {boolean} the query result
- */
- function isScaledElement(element) {
- if (!element || !isHTMLElement(element)) return false;
- const { width, height } = getBoundingClientRect(element);
- const { offsetWidth, offsetHeight } = element;
- return Math.round(width) !== offsetWidth
- || Math.round(height) !== offsetHeight;
- }
-
- /**
- * Returns the rect relative to an offset parent.
- * @see https://github.com/floating-ui/floating-ui
- *
- * @param {HTMLElement} element target
- * @param {ParentNode | Window} offsetParent the container / offset parent
- * @param {{x: number, y: number}} scroll the offsetParent scroll position
- * @returns {SHORTY.OffsetRect}
- */
- function getRectRelativeToOffsetParent(element, offsetParent, scroll) {
- const isParentAnElement = isHTMLElement(offsetParent);
- const rect = getBoundingClientRect(element, isParentAnElement && isScaledElement(offsetParent));
- const offsets = { x: 0, y: 0 };
-
- /* istanbul ignore next */
- if (isParentAnElement) {
- const offsetRect = getBoundingClientRect(offsetParent, true);
- offsets.x = offsetRect.x + offsetParent.clientLeft;
- offsets.y = offsetRect.y + offsetParent.clientTop;
- }
-
- return {
- x: rect.left + scroll.x - offsets.x,
- y: rect.top + scroll.y - offsets.y,
- width: rect.width,
- height: rect.height,
- };
- }
-
- /** @type {Record<string, string>} */
- const tipClassPositions = {
- top: 'top',
- bottom: 'bottom',
- left: 'start',
- right: 'end',
- };
-
- /**
- * Style popovers and tooltips.
- * @param {BSN.Tooltip | BSN.Popover} self the `Popover` / `Tooltip` instance
- * @param {PointerEvent=} e event object
- */
- function styleTip(self, e) {
- const tipClasses = /\b(top|bottom|start|end)+/;
- const {
- element, tooltip, options, arrow, offsetParent,
- } = self;
- const tipPositions = { ...tipClassPositions };
-
- const RTL = isRTL(element);
- if (RTL) {
- tipPositions.left = 'end';
- tipPositions.right = 'start';
- }
-
- // reset tooltip style (top: 0, left: 0 works best)
- setElementStyle(tooltip, {
- // top: '0px', left: '0px', right: '', bottom: '',
- top: '', left: '', right: '', bottom: '',
- });
- const isPopover = self.name === popoverComponent;
- const {
- offsetWidth: tipWidth, offsetHeight: tipHeight,
- } = tooltip;
- const {
- clientWidth: htmlcw, clientHeight: htmlch,
- } = getDocumentElement(element);
- const { container } = options;
- let { placement } = options;
- const {
- left: parentLeft, right: parentRight, top: parentTop,
- } = getBoundingClientRect(container, true);
- const {
- clientWidth: parentCWidth, offsetWidth: parentOWidth,
- } = container;
- const scrollbarWidth = Math.abs(parentCWidth - parentOWidth);
- // const tipAbsolute = getElementStyle(tooltip, 'position') === 'absolute';
- const parentPosition = getElementStyle(container, 'position');
- // const absoluteParent = parentPosition === 'absolute';
- const fixedParent = parentPosition === 'fixed';
- const staticParent = parentPosition === 'static';
- const stickyParent = parentPosition === 'sticky';
- const isSticky = stickyParent && parentTop === parseFloat(getElementStyle(container, 'top'));
- // const absoluteTarget = getElementStyle(element, 'position') === 'absolute';
- // const stickyFixedParent = ['sticky', 'fixed'].includes(parentPosition);
- const leftBoundry = RTL && fixedParent ? scrollbarWidth : 0;
- const rightBoundry = fixedParent ? parentCWidth + parentLeft + (RTL ? scrollbarWidth : 0)
- : parentCWidth + parentLeft + (htmlcw - parentRight) - 1;
- const {
- width: elemWidth,
- height: elemHeight,
- left: elemRectLeft,
- right: elemRectRight,
- top: elemRectTop,
- } = getBoundingClientRect(element, true);
-
- const scroll = getNodeScroll(offsetParent);
- const { x, y } = getRectRelativeToOffsetParent(element, offsetParent, scroll);
- // reset arrow style
- setElementStyle(arrow, {
- top: '', left: '', right: '', bottom: '',
- });
- let topPosition;
- let leftPosition;
- let rightPosition;
- let arrowTop;
- let arrowLeft;
- let arrowRight;
-
- const arrowWidth = arrow.offsetWidth || 0;
- const arrowHeight = arrow.offsetHeight || 0;
- const arrowAdjust = arrowWidth / 2;
-
- // check placement
- let topExceed = elemRectTop - tipHeight - arrowHeight < 0;
- let bottomExceed = elemRectTop + tipHeight + elemHeight
- + arrowHeight >= htmlch;
- let leftExceed = elemRectLeft - tipWidth - arrowWidth < leftBoundry;
- let rightExceed = elemRectLeft + tipWidth + elemWidth
- + arrowWidth >= rightBoundry;
-
- const horizontal = ['left', 'right'];
- const vertical = ['top', 'bottom'];
-
- topExceed = horizontal.includes(placement)
- ? elemRectTop + elemHeight / 2 - tipHeight / 2 - arrowHeight < 0
- : topExceed;
- bottomExceed = horizontal.includes(placement)
- ? elemRectTop + tipHeight / 2 + elemHeight / 2 + arrowHeight >= htmlch
- : bottomExceed;
- leftExceed = vertical.includes(placement)
- ? elemRectLeft + elemWidth / 2 - tipWidth / 2 < leftBoundry
- : leftExceed;
- rightExceed = vertical.includes(placement)
- ? elemRectLeft + tipWidth / 2 + elemWidth / 2 >= rightBoundry
- : rightExceed;
-
- // first remove side positions if both left and right limits are exceeded
- // we usually fall back to top|bottom
- placement = (horizontal.includes(placement)) && leftExceed && rightExceed ? 'top' : placement;
- // second, recompute placement
- placement = placement === 'top' && topExceed ? 'bottom' : placement;
- placement = placement === 'bottom' && bottomExceed ? 'top' : placement;
- placement = placement === 'left' && leftExceed ? 'right' : placement;
- placement = placement === 'right' && rightExceed ? 'left' : placement;
-
- // update tooltip/popover class
- if (!tooltip.className.includes(placement)) {
- tooltip.className = tooltip.className.replace(tipClasses, tipPositions[placement]);
- }
-
- // compute tooltip / popover coordinates
- /* istanbul ignore else */
- if (horizontal.includes(placement)) { // secondary|side positions
- if (placement === 'left') { // LEFT
- leftPosition = x - tipWidth - (isPopover ? arrowWidth : 0);
- } else { // RIGHT
- leftPosition = x + elemWidth + (isPopover ? arrowWidth : 0);
- }
-
- // adjust top and arrow
- if (topExceed) {
- topPosition = y;
- topPosition += (isSticky ? -parentTop - scroll.y : 0);
-
- arrowTop = elemHeight / 2 - arrowWidth;
- } else if (bottomExceed) {
- topPosition = y - tipHeight + elemHeight;
- topPosition += (isSticky ? -parentTop - scroll.y : 0);
-
- arrowTop = tipHeight - elemHeight / 2 - arrowWidth;
- } else {
- topPosition = y - tipHeight / 2 + elemHeight / 2;
- topPosition += (isSticky ? -parentTop - scroll.y : 0);
-
- arrowTop = tipHeight / 2 - arrowHeight / 2;
- }
- } else if (vertical.includes(placement)) {
- if (e && isMedia(element)) {
- let eX = 0;
- let eY = 0;
- if (staticParent) {
- eX = e.pageX;
- eY = e.pageY;
- } else { // fixedParent | stickyParent
- eX = e.clientX - parentLeft + (fixedParent ? scroll.x : 0);
- eY = e.clientY - parentTop + (fixedParent ? scroll.y : 0);
- }
-
- // some weird RTL bug
- eX -= RTL && fixedParent && scrollbarWidth ? scrollbarWidth : 0;
-
- if (placement === 'top') {
- topPosition = eY - tipHeight - arrowWidth;
- } else {
- topPosition = eY + arrowWidth;
- }
-
- // adjust (left | right) and also the arrow
- if (e.clientX - tipWidth / 2 < leftBoundry) {
- leftPosition = 0;
- arrowLeft = eX - arrowAdjust;
- } else if (e.clientX + tipWidth / 2 > rightBoundry) {
- leftPosition = 'auto';
- rightPosition = 0;
- arrowRight = rightBoundry - eX - arrowAdjust;
- arrowRight -= fixedParent ? parentLeft + (RTL ? scrollbarWidth : 0) : 0;
-
- // normal top/bottom
- } else {
- leftPosition = eX - tipWidth / 2;
- arrowLeft = tipWidth / 2 - arrowAdjust;
- }
- } else {
- if (placement === 'top') {
- topPosition = y - tipHeight - (isPopover ? arrowHeight : 0);
- } else { // BOTTOM
- topPosition = y + elemHeight + (isPopover ? arrowHeight : 0);
- }
-
- // adjust left | right and also the arrow
- if (leftExceed) {
- leftPosition = 0;
- arrowLeft = x + elemWidth / 2 - arrowAdjust;
- } else if (rightExceed) {
- leftPosition = 'auto';
- rightPosition = 0;
- arrowRight = elemWidth / 2 + rightBoundry - elemRectRight - arrowAdjust;
- } else {
- leftPosition = x - tipWidth / 2 + elemWidth / 2;
- arrowLeft = tipWidth / 2 - arrowAdjust;
- }
- }
- }
-
- // apply style to tooltip/popover
- setElementStyle(tooltip, {
- top: `${topPosition}px`,
- left: leftPosition === 'auto' ? leftPosition : `${leftPosition}px`,
- right: rightPosition !== undefined ? `${rightPosition}px` : '',
- });
-
- // update arrow placement
- /* istanbul ignore else */
- if (isHTMLElement(arrow)) {
- if (arrowTop !== undefined) {
- arrow.style.top = `${arrowTop}px`;
- }
- if (arrowLeft !== undefined) {
- arrow.style.left = `${arrowLeft}px`;
- } else if (arrowRight !== undefined) {
- arrow.style.right = `${arrowRight}px`;
- }
- }
- }
-
- const tooltipDefaults = {
- /** @type {string} */
- template: getTipTemplate(tooltipString),
- /** @type {string?} */
- title: null, // string
- /** @type {string?} */
- customClass: null, // string | null
- /** @type {string} */
- trigger: 'hover focus',
- /** @type {string?} */
- placement: 'top', // string
- /** @type {((c:string)=>string)?} */
- sanitizeFn: null, // function
- /** @type {boolean} */
- animation: true, // bool
- /** @type {number} */
- delay: 200, // number
- /** @type {HTMLElement?} */
- container: null,
- };
-
- /**
- * A global namespace for aria-describedby.
- * @type {string}
- */
- const ariaDescribedBy = 'aria-describedby';
-
- /**
- * A global namespace for `mousedown` event.
- * @type {string}
- */
- const mousedownEvent = 'mousedown';
-
- /**
- * A global namespace for `mousemove` event.
- * @type {string}
- */
- const mousemoveEvent = 'mousemove';
-
- /**
- * A global namespace for `focusin` event.
- * @type {string}
- */
- const focusinEvent = 'focusin';
-
- /**
- * A global namespace for `focusout` event.
- * @type {string}
- */
- const focusoutEvent = 'focusout';
-
- /**
- * A global namespace for `hover` event.
- * @type {string}
- */
- const mousehoverEvent = 'hover';
-
- /**
- * A global namespace for `touchstart` event.
- * @type {string}
- */
- const touchstartEvent = 'touchstart';
-
- let elementUID = 0;
- let elementMapUID = 0;
- const elementIDMap = new Map();
-
- /**
- * Returns a unique identifier for popover, tooltip, scrollspy.
- *
- * @param {HTMLElement} element target element
- * @param {string=} key predefined key
- * @returns {number} an existing or new unique ID
- */
- function getUID(element, key) {
- let result = key ? elementUID : elementMapUID;
-
- if (key) {
- const elID = getUID(element);
- const elMap = elementIDMap.get(elID) || new Map();
- if (!elementIDMap.has(elID)) {
- elementIDMap.set(elID, elMap);
- }
- if (!elMap.has(key)) {
- elMap.set(key, result);
- elementUID += 1;
- } else result = elMap.get(key);
- } else {
- const elkey = element.id || element;
-
- if (!elementIDMap.has(elkey)) {
- elementIDMap.set(elkey, result);
- elementMapUID += 1;
- } else result = elementIDMap.get(elkey);
- }
- return result;
- }
-
- /**
- * Checks if an object is a `Function`.
- *
- * @param {any} fn the target object
- * @returns {boolean} the query result
- */
- const isFunction = (fn) => (fn && fn.constructor.name === 'Function') || false;
-
- const { userAgentData: uaDATA } = navigator;
-
- /**
- * A global namespace for `userAgentData` object.
- */
- const userAgentData = uaDATA;
-
- const { userAgent: userAgentString } = navigator;
-
- /**
- * A global namespace for `navigator.userAgent` string.
- */
- const userAgent = userAgentString;
-
- const appleBrands = /(iPhone|iPod|iPad)/;
-
- /**
- * A global `boolean` for Apple browsers.
- * @type {boolean}
- */
- const isApple = userAgentData ? userAgentData.brands.some((x) => appleBrands.test(x.brand))
- : /* istanbul ignore next */appleBrands.test(userAgent);
-
- /**
- * Global namespace for `data-bs-title` attribute.
- */
- const dataOriginalTitle = 'data-original-title';
-
- /** @type {string} */
- const tooltipComponent = 'Tooltip';
-
- /**
- * Checks if an object is a `NodeList`.
- * => equivalent to `object instanceof NodeList`
- *
- * @param {any} object the target object
- * @returns {boolean} the query result
- */
- const isNodeList = (object) => (object && object.constructor.name === 'NodeList') || false;
-
- /**
- * Shortcut for `typeof SOMETHING === "string"`.
- *
- * @param {any} str input value
- * @returns {boolean} the query result
- */
- const isString = (str) => typeof str === 'string';
-
- /**
- * Shortcut for `Array.isArray()` static method.
- *
- * @param {any} arr array-like iterable object
- * @returns {boolean} the query result
- */
- const isArray = (arr) => Array.isArray(arr);
-
- /**
- * Append an existing `Element` to Popover / Tooltip component or HTML
- * markup string to be parsed & sanitized to be used as popover / tooltip content.
- *
- * @param {HTMLElement} element target
- * @param {Node | string} content the `Element` to append / string
- * @param {ReturnType<any>} sanitizeFn a function to sanitize string content
- */
- function setHtml(element, content, sanitizeFn) {
- /* istanbul ignore next */
- if (!isHTMLElement(element) || (isString(content) && !content.length)) return;
-
- /* istanbul ignore else */
- if (isString(content)) {
- let dirty = content.trim(); // fixing #233
- if (isFunction(sanitizeFn)) dirty = sanitizeFn(dirty);
-
- const win = getWindow(element);
- const domParser = new win.DOMParser();
- const tempDocument = domParser.parseFromString(dirty, 'text/html');
- element.append(...[...tempDocument.body.childNodes]);
- } else if (isHTMLElement(content)) {
- element.append(content);
- } else if (isNodeList(content)
- || (isArray(content) && content.every(isNode))) {
- element.append(...[...content]);
- }
- }
-
- /**
- * Creates a new tooltip / popover.
- *
- * @param {BSN.Popover | BSN.Tooltip} self the `Tooltip` / `Popover` instance
- */
- function createTip(self) {
- const { id, element, options } = self;
- const {
- animation, customClass, sanitizeFn, placement, dismissible,
- title, content, template, btnClose,
- } = options;
- const isTooltip = self.name === tooltipComponent;
- const tipString = isTooltip ? tooltipString : popoverString;
- const tipPositions = { ...tipClassPositions };
- let titleParts = [];
- let contentParts = [];
-
- if (isRTL(element)) {
- tipPositions.left = 'end';
- tipPositions.right = 'start';
- }
-
- // set initial popover class
- const placementClass = `bs-${tipString}-${tipPositions[placement]}`;
-
- // load template
- /** @type {HTMLElement?} */
- let tooltipTemplate;
- if (isHTMLElement(template)) {
- tooltipTemplate = template;
- } else {
- const htmlMarkup = createElement('div');
- setHtml(htmlMarkup, template, sanitizeFn);
- tooltipTemplate = htmlMarkup.firstChild;
- }
-
- // set popover markup
- self.tooltip = isHTMLElement(tooltipTemplate) && tooltipTemplate.cloneNode(true);
-
- const { tooltip } = self;
-
- // set id and role attributes
- setAttribute(tooltip, 'id', id);
- setAttribute(tooltip, 'role', tooltipString);
-
- const bodyClass = isTooltip ? `${tooltipString}-inner` : `${popoverString}-body`;
- const tooltipHeader = isTooltip ? null : querySelector(`.${popoverString}-header`, tooltip);
- const tooltipBody = querySelector(`.${bodyClass}`, tooltip);
-
- // set arrow and enable access for styleTip
- self.arrow = querySelector(`.${tipString}-arrow`, tooltip);
- const { arrow } = self;
-
- if (isHTMLElement(title)) titleParts = [title.cloneNode(true)];
- else {
- const tempTitle = createElement('div');
- setHtml(tempTitle, title, sanitizeFn);
- titleParts = [...[...tempTitle.childNodes]];
- }
-
- if (isHTMLElement(content)) contentParts = [content.cloneNode(true)];
- else {
- const tempContent = createElement('div');
- setHtml(tempContent, content, sanitizeFn);
- contentParts = [...[...tempContent.childNodes]];
- }
-
- // set dismissible button
- if (dismissible) {
- if (title) {
- if (isHTMLElement(btnClose)) titleParts = [...titleParts, btnClose.cloneNode(true)];
- else {
- const tempBtn = createElement('div');
- setHtml(tempBtn, btnClose, sanitizeFn);
- titleParts = [...titleParts, tempBtn.firstChild];
- }
- } else {
- /* istanbul ignore else */
- if (tooltipHeader) tooltipHeader.remove();
- if (isHTMLElement(btnClose)) contentParts = [...contentParts, btnClose.cloneNode(true)];
- else {
- const tempBtn = createElement('div');
- setHtml(tempBtn, btnClose, sanitizeFn);
- contentParts = [...contentParts, tempBtn.firstChild];
- }
- }
- }
-
- // fill the template with content from options / data attributes
- // also sanitize title && content
- /* istanbul ignore else */
- if (!isTooltip) {
- /* istanbul ignore else */
- if (title && tooltipHeader) setHtml(tooltipHeader, titleParts, sanitizeFn);
- /* istanbul ignore else */
- if (content && tooltipBody) setHtml(tooltipBody, contentParts, sanitizeFn);
- // set btn
- self.btn = querySelector('.btn-close', tooltip);
- } else if (title && tooltipBody) setHtml(tooltipBody, title, sanitizeFn);
-
- // Bootstrap 5.2.x
- addClass(tooltip, 'position-absolute');
- addClass(arrow, 'position-absolute');
-
- // set popover animation and placement
- /* istanbul ignore else */
- if (!hasClass(tooltip, tipString)) addClass(tooltip, tipString);
- /* istanbul ignore else */
- if (animation && !hasClass(tooltip, fadeClass)) addClass(tooltip, fadeClass);
- /* istanbul ignore else */
- if (customClass && !hasClass(tooltip, customClass)) {
- addClass(tooltip, customClass);
- }
- /* istanbul ignore else */
- if (!hasClass(tooltip, placementClass)) addClass(tooltip, placementClass);
- }
-
- /**
- * @param {HTMLElement} tip target
- * @param {ParentNode} container parent container
- * @returns {boolean}
- */
- function isVisibleTip(tip, container) {
- return isHTMLElement(tip) && container.contains(tip);
- }
-
- /* Native JavaScript for Bootstrap 5 | Tooltip
- ---------------------------------------------- */
-
- // TOOLTIP PRIVATE GC
- // ==================
- const tooltipSelector = `[${dataBsToggle}="${tooltipString}"],[data-tip="${tooltipString}"]`;
- const titleAttr = 'title';
-
- /**
- * Static method which returns an existing `Tooltip` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Tooltip>}
- */
- let getTooltipInstance = (element) => getInstance(element, tooltipComponent);
-
- /**
- * A `Tooltip` initialization callback.
- * @type {BSN.InitCallback<Tooltip>}
- */
- const tooltipInitCallback = (element) => new Tooltip(element);
-
- // TOOLTIP PRIVATE METHODS
- // =======================
- /**
- * Removes the tooltip from the DOM.
- *
- * @param {Tooltip} self the `Tooltip` instance
- */
- function removeTooltip(self) {
- const { element, tooltip } = self;
- removeAttribute(element, ariaDescribedBy);
- tooltip.remove();
- }
-
- /**
- * Executes after the instance has been disposed.
- *
- * @param {Tooltip} self the `Tooltip` instance
- * @param {Function=} callback the parent dispose callback
- */
- function disposeTooltipComplete(self, callback) {
- const { element } = self;
- toggleTooltipHandlers(self);
-
- /* istanbul ignore else */
- if (hasAttribute(element, dataOriginalTitle) && self.name === tooltipComponent) {
- toggleTooltipTitle(self);
- }
- /* istanbul ignore else */
- if (callback) callback();
- }
-
- /**
- * Toggles on/off the special `Tooltip` event listeners.
- *
- * @param {Tooltip} self the `Tooltip` instance
- * @param {boolean=} add when `true`, event listeners are added
- */
- function toggleTooltipAction(self, add) {
- const action = add ? addListener : removeListener;
- const { element } = self;
-
- action(getDocument(element), touchstartEvent, self.handleTouch, passiveHandler);
-
- /* istanbul ignore else */
- if (!isMedia(element)) {
- [scrollEvent, resizeEvent].forEach((ev) => {
- action(getWindow(element), ev, self.update, passiveHandler);
- });
- }
- }
-
- /**
- * Executes after the tooltip was shown to the user.
- *
- * @param {Tooltip} self the `Tooltip` instance
- */
- function tooltipShownAction(self) {
- const { element } = self;
- const shownTooltipEvent = OriginalEvent(`shown.bs.${toLowerCase(self.name)}`);
-
- toggleTooltipAction(self, true);
- dispatchEvent(element, shownTooltipEvent);
- Timer.clear(element, 'in');
- }
-
- /**
- * Executes after the tooltip was hidden to the user.
- *
- * @param {Tooltip} self the `Tooltip` instance
- * @param {Function=} callback the dispose callback
- */
- function tooltipHiddenAction(self, callback) {
- const { element } = self;
- const hiddenTooltipEvent = OriginalEvent(`hidden.bs.${toLowerCase(self.name)}`);
-
- toggleTooltipAction(self);
- removeTooltip(self);
- dispatchEvent(element, hiddenTooltipEvent);
- if (isFunction(callback)) callback();
- Timer.clear(element, 'out');
- }
-
- /**
- * Toggles on/off the `Tooltip` event listeners.
- *
- * @param {Tooltip} self the `Tooltip` instance
- * @param {boolean=} add when `true`, event listeners are added
- */
- function toggleTooltipHandlers(self, add) {
- const action = add ? addListener : removeListener;
- // btn is only for dismissible popover
- const { element, options, btn } = self;
- const { trigger, dismissible } = options;
-
- if (trigger.includes('manual')) return;
-
- self.enabled = !!add;
-
- /** @type {string[]} */
- const triggerOptions = trigger.split(' ');
- const elemIsMedia = isMedia(element);
-
- if (elemIsMedia) {
- action(element, mousemoveEvent, self.update, passiveHandler);
- }
-
- triggerOptions.forEach((tr) => {
- /* istanbul ignore else */
- if (elemIsMedia || tr === mousehoverEvent) {
- action(element, mousedownEvent, self.show);
- action(element, mouseenterEvent, self.show);
-
- /* istanbul ignore else */
- if (dismissible && btn) {
- action(btn, mouseclickEvent, self.hide);
- } else {
- action(element, mouseleaveEvent, self.hide);
- action(getDocument(element), touchstartEvent, self.handleTouch, passiveHandler);
- }
- } else if (tr === mouseclickEvent) {
- action(element, tr, (!dismissible ? self.toggle : self.show));
- } else if (tr === focusEvent) {
- action(element, focusinEvent, self.show);
- /* istanbul ignore else */
- if (!dismissible) action(element, focusoutEvent, self.hide);
- /* istanbul ignore else */
- if (isApple) {
- action(element, mouseclickEvent, () => focus(element));
- }
- }
- });
- }
-
- /**
- * Toggles on/off the `Tooltip` event listeners that hide/update the tooltip.
- *
- * @param {Tooltip} self the `Tooltip` instance
- * @param {boolean=} add when `true`, event listeners are added
- */
- function toggleTooltipOpenHandlers(self, add) {
- const action = add ? addListener : removeListener;
- const { element, options, offsetParent } = self;
- const { container } = options;
- const { offsetHeight, scrollHeight } = container;
- const parentModal = closest(element, `.${modalString}`);
- const parentOffcanvas = closest(element, `.${offcanvasString}`);
-
- /* istanbul ignore else */
- if (!isMedia(element)) {
- const win = getWindow(element);
- const overflow = offsetHeight !== scrollHeight;
- const scrollTarget = overflow || offsetParent !== win ? container : win;
- action(win, resizeEvent, self.update, passiveHandler);
- action(scrollTarget, scrollEvent, self.update, passiveHandler);
- }
-
- // dismiss tooltips inside modal / offcanvas
- if (parentModal) action(parentModal, `hide.bs.${modalString}`, self.hide);
- if (parentOffcanvas) action(parentOffcanvas, `hide.bs.${offcanvasString}`, self.hide);
- }
-
- /**
- * Toggles the `title` and `data-original-title` attributes.
- *
- * @param {Tooltip} self the `Tooltip` instance
- * @param {string=} content when `true`, event listeners are added
- */
- function toggleTooltipTitle(self, content) {
- // [0 - add, 1 - remove] | [0 - remove, 1 - add]
- const titleAtt = [dataOriginalTitle, titleAttr];
- const { element } = self;
-
- setAttribute(element, titleAtt[content ? 0 : 1],
- (content || getAttribute(element, titleAtt[0])));
- removeAttribute(element, titleAtt[content ? 1 : 0]);
- }
-
- // TOOLTIP DEFINITION
- // ==================
- /** Creates a new `Tooltip` instance. */
- class Tooltip extends BaseComponent {
- /**
- * @param {HTMLElement | string} target the target element
- * @param {BSN.Options.Tooltip=} config the instance options
- */
- constructor(target, config) {
- super(target, config);
-
- // bind
- const self = this;
- const { element } = self;
- const isTooltip = self.name === tooltipComponent;
- const tipString = isTooltip ? tooltipString : popoverString;
- const tipComponent = isTooltip ? tooltipComponent : popoverComponent;
-
- /* istanbul ignore next: this is to set Popover too */
- getTooltipInstance = (elem) => getInstance(elem, tipComponent);
-
- // additional properties
- /** @type {any} */
- self.tooltip = {};
- if (!isTooltip) {
- /** @type {any?} */
- self.btn = null;
- }
- /** @type {any} */
- self.arrow = {};
- /** @type {any} */
- self.offsetParent = {};
- /** @type {boolean} */
- self.enabled = true;
- /** @type {string} Set unique ID for `aria-describedby`. */
- self.id = `${tipString}-${getUID(element, tipString)}`;
-
- // instance options
- const { options } = self;
-
- // invalidate
- if ((!options.title && isTooltip) || (!isTooltip && !options.content)) {
- // throw Error(`${this.name} Error: target has no content set.`);
- return;
- }
-
- const container = querySelector(options.container, getDocument(element));
- const idealContainer = getElementContainer(element);
-
- // bypass container option when its position is static/relative
- self.options.container = !container || (container
- && ['static', 'relative'].includes(getElementStyle(container, 'position')))
- ? idealContainer
- : /* istanbul ignore next */container || getDocumentBody(element);
-
- // reset default options
- tooltipDefaults[titleAttr] = null;
-
- // all functions bind
- self.handleTouch = self.handleTouch.bind(self);
- self.update = self.update.bind(self);
- self.show = self.show.bind(self);
- self.hide = self.hide.bind(self);
- self.toggle = self.toggle.bind(self);
-
- // set title attributes and add event listeners
- /* istanbul ignore else */
- if (hasAttribute(element, titleAttr) && isTooltip) {
- toggleTooltipTitle(self, options.title);
- }
-
- // create tooltip here
- createTip(self);
-
- // attach events
- toggleTooltipHandlers(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return tooltipComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return tooltipDefaults; }
- /* eslint-enable */
-
- // TOOLTIP PUBLIC METHODS
- // ======================
- /**
- * Shows the tooltip.
- *
- * @param {Event=} e the `Event` object
- * @this {Tooltip}
- */
- show(e) {
- const self = this;
- const {
- options, tooltip, element, id,
- } = self;
- const { container, animation } = options;
- const outTimer = Timer.get(element, 'out');
-
- Timer.clear(element, 'out');
-
- if (tooltip && !outTimer && !isVisibleTip(tooltip, container)) {
- Timer.set(element, () => {
- const showTooltipEvent = OriginalEvent(`show.bs.${toLowerCase(self.name)}`);
- dispatchEvent(element, showTooltipEvent);
- if (showTooltipEvent.defaultPrevented) return;
-
- // append to container
- container.append(tooltip);
- setAttribute(element, ariaDescribedBy, `#${id}`);
- // set offsetParent
- self.offsetParent = getElementContainer(tooltip, true);
-
- self.update(e);
- toggleTooltipOpenHandlers(self, true);
-
- /* istanbul ignore else */
- if (!hasClass(tooltip, showClass)) addClass(tooltip, showClass);
- /* istanbul ignore else */
- if (animation) emulateTransitionEnd(tooltip, () => tooltipShownAction(self));
- else tooltipShownAction(self);
- }, 17, 'in');
- }
- }
-
- /**
- * Hides the tooltip.
- *
- * @this {Tooltip} the Tooltip instance
- * @param {Function=} callback the dispose callback
- */
- hide(callback) {
- const self = this;
- const { options, tooltip, element } = self;
- const { container, animation, delay } = options;
-
- Timer.clear(element, 'in');
-
- /* istanbul ignore else */
- if (tooltip && isVisibleTip(tooltip, container)) {
- Timer.set(element, () => {
- const hideTooltipEvent = OriginalEvent(`hide.bs.${toLowerCase(self.name)}`);
- dispatchEvent(element, hideTooltipEvent);
-
- if (hideTooltipEvent.defaultPrevented) return;
-
- removeClass(tooltip, showClass);
- toggleTooltipOpenHandlers(self);
-
- /* istanbul ignore else */
- if (animation) emulateTransitionEnd(tooltip, () => tooltipHiddenAction(self, callback));
- else tooltipHiddenAction(self, callback);
- }, delay + 17, 'out');
- }
- }
-
- /**
- * Updates the tooltip position.
- *
- * @param {Event=} e the `Event` object
- * @this {Tooltip} the `Tooltip` instance
- */
- update(e) {
- styleTip(this, e);
- }
-
- /**
- * Toggles the tooltip visibility.
- *
- * @param {Event=} e the `Event` object
- * @this {Tooltip} the instance
- */
- toggle(e) {
- const self = this;
- const { tooltip, options } = self;
-
- if (!isVisibleTip(tooltip, options.container)) self.show(e);
- else self.hide();
- }
-
- /** Enables the tooltip. */
- enable() {
- const self = this;
- const { enabled } = self;
- /* istanbul ignore else */
- if (!enabled) {
- toggleTooltipHandlers(self, true);
- self.enabled = !enabled;
- }
- }
-
- /** Disables the tooltip. */
- disable() {
- const self = this;
- const {
- tooltip, options, enabled,
- } = self;
- const { animation, container } = options;
- /* istanbul ignore else */
- if (enabled) {
- if (isVisibleTip(tooltip, container) && animation) {
- self.hide(() => toggleTooltipHandlers(self));
- } else {
- toggleTooltipHandlers(self);
- }
- self.enabled = !enabled;
- }
- }
-
- /** Toggles the `disabled` property. */
- toggleEnabled() {
- const self = this;
- if (!self.enabled) self.enable();
- else self.disable();
- }
-
- /**
- * Handles the `touchstart` event listener for `Tooltip`
- * @this {Tooltip}
- * @param {TouchEvent} e the `Event` object
- */
- handleTouch({ target }) {
- const { tooltip, element } = this;
-
- /* istanbul ignore next */
- if (tooltip.contains(target) || target === element
- || (target && element.contains(target))) ; else {
- this.hide();
- }
- }
-
- /** Removes the `Tooltip` from the target element. */
- dispose() {
- const self = this;
- const { tooltip, options } = self;
- const callback = () => disposeTooltipComplete(self, () => super.dispose());
-
- if (options.animation && isVisibleTip(tooltip, options.container)) {
- self.options.delay = 0; // reset delay
- self.hide(callback);
- } else {
- callback();
- }
- }
- }
-
- ObjectAssign(Tooltip, {
- selector: tooltipSelector,
- init: tooltipInitCallback,
- getInstance: getTooltipInstance,
- styleTip,
- });
-
- /* Native JavaScript for Bootstrap 5 | Popover
- ---------------------------------------------- */
-
- // POPOVER PRIVATE GC
- // ==================
- const popoverSelector = `[${dataBsToggle}="${popoverString}"],[data-tip="${popoverString}"]`;
-
- const popoverDefaults = {
- ...tooltipDefaults,
- /** @type {string} */
- template: getTipTemplate(popoverString),
- /** @type {string} */
- btnClose: '<button class="btn-close" aria-label="Close"></button>',
- /** @type {boolean} */
- dismissible: false,
- /** @type {string?} */
- content: null,
- };
-
- // POPOVER DEFINITION
- // ==================
- /** Returns a new `Popover` instance. */
- class Popover extends Tooltip {
- /* eslint-disable -- we want to specify Popover Options */
- /**
- * @param {HTMLElement | string} target the target element
- * @param {BSN.Options.Popover=} config the instance options
- */
- constructor(target, config) {
- super(target, config);
- }
- /**
- * Returns component name string.
- */
- get name() { return popoverComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return popoverDefaults; }
- /* eslint-enable */
-
- /* extend original `show()` */
- show() {
- super.show();
- // btn only exists within dismissible popover
- const { options, btn } = this;
- /* istanbul ignore else */
- if (options.dismissible && btn) setTimeout(() => focus(btn), 17);
- }
- }
-
- /**
- * Static method which returns an existing `Popover` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Popover>}
- */
- const getPopoverInstance = (element) => getInstance(element, popoverComponent);
-
- /**
- * A `Popover` initialization callback.
- * @type {BSN.InitCallback<Popover>}
- */
- const popoverInitCallback = (element) => new Popover(element);
-
- ObjectAssign(Popover, {
- selector: popoverSelector,
- init: popoverInitCallback,
- getInstance: getPopoverInstance,
- styleTip,
- });
-
- /**
- * Shortcut for `HTMLElement.getElementsByTagName` method. Some `Node` elements
- * like `ShadowRoot` do not support `getElementsByTagName`.
- *
- * @param {string} selector the tag name
- * @param {ParentNode=} parent optional Element to look into
- * @return {HTMLCollectionOf<HTMLElement>} the 'HTMLCollection'
- */
- function getElementsByTagName(selector, parent) {
- const lookUp = isNode(parent) ? parent : getDocument();
- return lookUp.getElementsByTagName(selector);
- }
-
- /** @type {string} */
- const scrollspyString = 'scrollspy';
-
- /** @type {string} */
- const scrollspyComponent = 'ScrollSpy';
-
- /* Native JavaScript for Bootstrap 5 | ScrollSpy
- ------------------------------------------------ */
-
- // SCROLLSPY PRIVATE GC
- // ====================
- const scrollspySelector = '[data-bs-spy="scroll"]';
-
- const scrollspyDefaults = {
- offset: 10,
- target: null,
- };
-
- /**
- * Static method which returns an existing `ScrollSpy` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<ScrollSpy>}
- */
- const getScrollSpyInstance = (element) => getInstance(element, scrollspyComponent);
-
- /**
- * A `ScrollSpy` initialization callback.
- * @type {BSN.InitCallback<ScrollSpy>}
- */
- const scrollspyInitCallback = (element) => new ScrollSpy(element);
-
- // SCROLLSPY CUSTOM EVENT
- // ======================
- const activateScrollSpy = OriginalEvent(`activate.bs.${scrollspyString}`);
-
- // SCROLLSPY PRIVATE METHODS
- // =========================
- /**
- * Update the state of all items.
- * @param {ScrollSpy} self the `ScrollSpy` instance
- */
- function updateSpyTargets(self) {
- const {
- target, scrollTarget, options, itemsLength, scrollHeight, element,
- } = self;
- const { offset } = options;
- const isWin = isWindow(scrollTarget);
-
- const links = target && getElementsByTagName('A', target);
- const scrollHEIGHT = scrollTarget && getScrollHeight(scrollTarget);
-
- self.scrollTop = isWin ? scrollTarget.scrollY : scrollTarget.scrollTop;
-
- // only update items/offsets once or with each mutation
- /* istanbul ignore else */
- if (links && (itemsLength !== links.length || scrollHEIGHT !== scrollHeight)) {
- let href;
- let targetItem;
- let rect;
-
- // reset arrays & update
- self.items = [];
- self.offsets = [];
- self.scrollHeight = scrollHEIGHT;
- self.maxScroll = self.scrollHeight - getOffsetHeight(self);
-
- [...links].forEach((link) => {
- href = getAttribute(link, 'href');
- targetItem = href && href.charAt(0) === '#' && href.slice(-1) !== '#'
- && querySelector(href, getDocument(element));
-
- if (targetItem) {
- self.items.push(link);
- rect = getBoundingClientRect(targetItem);
- self.offsets.push((isWin ? rect.top + self.scrollTop : targetItem.offsetTop) - offset);
- }
- });
- self.itemsLength = self.items.length;
- }
- }
-
- /**
- * Returns the `scrollHeight` property of the scrolling element.
- * @param {Node | Window} scrollTarget the `ScrollSpy` instance
- * @return {number} `scrollTarget` height
- */
- function getScrollHeight(scrollTarget) {
- return isHTMLElement(scrollTarget)
- ? scrollTarget.scrollHeight
- : getDocumentElement(scrollTarget).scrollHeight;
- }
-
- /**
- * Returns the height property of the scrolling element.
- * @param {ScrollSpy} params the `ScrollSpy` instance
- * @returns {number}
- */
- function getOffsetHeight({ element, scrollTarget }) {
- return (isWindow(scrollTarget))
- ? scrollTarget.innerHeight
- : getBoundingClientRect(element).height;
- }
-
- /**
- * Clear all items of the target.
- * @param {HTMLElement} target a single item
- */
- function clear(target) {
- [...getElementsByTagName('A', target)].forEach((item) => {
- if (hasClass(item, activeClass)) removeClass(item, activeClass);
- });
- }
-
- /**
- * Activates a new item.
- * @param {ScrollSpy} self the `ScrollSpy` instance
- * @param {HTMLElement} item a single item
- */
- function activate(self, item) {
- const { target, element } = self;
- clear(target);
- self.activeItem = item;
- addClass(item, activeClass);
-
- // activate all parents
- const parents = [];
- let parentItem = item;
- while (parentItem !== getDocumentBody(element)) {
- parentItem = parentItem.parentElement;
- if (hasClass(parentItem, 'nav') || hasClass(parentItem, 'dropdown-menu')) parents.push(parentItem);
- }
-
- parents.forEach((menuItem) => {
- /** @type {HTMLElement?} */
- const parentLink = menuItem.previousElementSibling;
-
- /* istanbul ignore else */
- if (parentLink && !hasClass(parentLink, activeClass)) {
- addClass(parentLink, activeClass);
- }
- });
-
- // dispatch
- activateScrollSpy.relatedTarget = item;
- dispatchEvent(element, activateScrollSpy);
- }
-
- /**
- * Toggles on/off the component event listener.
- * @param {ScrollSpy} self the `ScrollSpy` instance
- * @param {boolean=} add when `true`, listener is added
- */
- function toggleSpyHandlers(self, add) {
- const action = add ? addListener : removeListener;
- action(self.scrollTarget, scrollEvent, self.refresh, passiveHandler);
- }
-
- // SCROLLSPY DEFINITION
- // ====================
- /** Returns a new `ScrollSpy` instance. */
- class ScrollSpy extends BaseComponent {
- /**
- * @param {HTMLElement | string} target the target element
- * @param {BSN.Options.ScrollSpy=} config the instance options
- */
- constructor(target, config) {
- super(target, config);
- // bind
- const self = this;
-
- // initialization element & options
- const { element, options } = self;
-
- // additional properties
- /** @type {HTMLElement?} */
- self.target = querySelector(options.target, getDocument(element));
-
- // invalidate
- if (!self.target) return;
-
- // set initial state
- /** @type {HTMLElement | Window} */
- self.scrollTarget = element.clientHeight < element.scrollHeight
- ? element : getWindow(element);
- /** @type {number} */
- self.scrollTop = 0;
- /** @type {number} */
- self.maxScroll = 0;
- /** @type {number} */
- self.scrollHeight = 0;
- /** @type {HTMLElement?} */
- self.activeItem = null;
- /** @type {HTMLElement[]} */
- self.items = [];
- /** @type {number} */
- self.itemsLength = 0;
- /** @type {number[]} */
- self.offsets = [];
-
- // bind events
- self.refresh = self.refresh.bind(self);
-
- // add event handlers
- toggleSpyHandlers(self, true);
-
- self.refresh();
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return scrollspyComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return scrollspyDefaults; }
- /* eslint-enable */
-
- // SCROLLSPY PUBLIC METHODS
- // ========================
- /** Updates all items. */
- refresh() {
- const self = this;
- const { target } = self;
-
- // check if target is visible and invalidate
- /* istanbul ignore next */
- if (target.offsetHeight === 0) return;
-
- updateSpyTargets(self);
-
- const {
- scrollTop, maxScroll, itemsLength, items, activeItem,
- } = self;
-
- if (scrollTop >= maxScroll) {
- const newActiveItem = items[itemsLength - 1];
-
- /* istanbul ignore else */
- if (activeItem !== newActiveItem) {
- activate(self, newActiveItem);
- }
- return;
- }
-
- const { offsets } = self;
-
- if (activeItem && scrollTop < offsets[0] && offsets[0] > 0) {
- self.activeItem = null;
- clear(target);
- return;
- }
-
- items.forEach((item, i) => {
- if (activeItem !== item && scrollTop >= offsets[i]
- && (typeof offsets[i + 1] === 'undefined' || scrollTop < offsets[i + 1])) {
- activate(self, item);
- }
- });
- }
-
- /** Removes `ScrollSpy` from the target element. */
- dispose() {
- toggleSpyHandlers(this);
- super.dispose();
- }
- }
-
- ObjectAssign(ScrollSpy, {
- selector: scrollspySelector,
- init: scrollspyInitCallback,
- getInstance: getScrollSpyInstance,
- });
-
- /**
- * A global namespace for aria-selected.
- * @type {string}
- */
- const ariaSelected = 'aria-selected';
-
- /** @type {string} */
- const tabString = 'tab';
-
- /** @type {string} */
- const tabComponent = 'Tab';
-
- /* Native JavaScript for Bootstrap 5 | Tab
- ------------------------------------------ */
-
- // TAB PRIVATE GC
- // ================
- const tabSelector = `[${dataBsToggle}="${tabString}"]`;
-
- /**
- * Static method which returns an existing `Tab` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Tab>}
- */
- const getTabInstance = (element) => getInstance(element, tabComponent);
-
- /**
- * A `Tab` initialization callback.
- * @type {BSN.InitCallback<Tab>}
- */
- const tabInitCallback = (element) => new Tab(element);
-
- // TAB CUSTOM EVENTS
- // =================
- const showTabEvent = OriginalEvent(`show.bs.${tabString}`);
- const shownTabEvent = OriginalEvent(`shown.bs.${tabString}`);
- const hideTabEvent = OriginalEvent(`hide.bs.${tabString}`);
- const hiddenTabEvent = OriginalEvent(`hidden.bs.${tabString}`);
-
- /**
- * Stores the current active tab and its content
- * for a given `.nav` element.
- * @type {Map<HTMLElement, any>}
- */
- const tabPrivate = new Map();
-
- // TAB PRIVATE METHODS
- // ===================
- /**
- * Executes after tab transition has finished.
- * @param {Tab} self the `Tab` instance
- */
- function triggerTabEnd(self) {
- const { tabContent, nav } = self;
-
- /* istanbul ignore else */
- if (tabContent && hasClass(tabContent, collapsingClass)) {
- tabContent.style.height = '';
- removeClass(tabContent, collapsingClass);
- }
-
- /* istanbul ignore else */
- if (nav) Timer.clear(nav);
- }
-
- /**
- * Executes before showing the tab content.
- * @param {Tab} self the `Tab` instance
- */
- function triggerTabShow(self) {
- const {
- element, tabContent, content: nextContent, nav,
- } = self;
- const { tab } = nav && tabPrivate.get(nav);
-
- /* istanbul ignore else */
- if (tabContent && hasClass(nextContent, fadeClass)) {
- const { currentHeight, nextHeight } = tabPrivate.get(element);
- if (currentHeight === nextHeight) {
- triggerTabEnd(self);
- } else {
- // enables height animation
- setTimeout(() => {
- tabContent.style.height = `${nextHeight}px`;
- reflow(tabContent);
- emulateTransitionEnd(tabContent, () => triggerTabEnd(self));
- }, 50);
- }
- } else if (nav) Timer.clear(nav);
-
- shownTabEvent.relatedTarget = tab;
- dispatchEvent(element, shownTabEvent);
- }
-
- /**
- * Executes before hiding the tab.
- * @param {Tab} self the `Tab` instance
- */
- function triggerTabHide(self) {
- const {
- element, content: nextContent, tabContent, nav,
- } = self;
- const { tab, content } = nav && tabPrivate.get(nav);
- let currentHeight = 0;
-
- /* istanbul ignore else */
- if (tabContent && hasClass(nextContent, fadeClass)) {
- [content, nextContent].forEach((c) => {
- addClass(c, 'overflow-hidden');
- });
- currentHeight = content.scrollHeight || /* istanbul ignore next */0;
- }
-
- // update relatedTarget and dispatch event
- showTabEvent.relatedTarget = tab;
- hiddenTabEvent.relatedTarget = element;
- dispatchEvent(element, showTabEvent);
- if (showTabEvent.defaultPrevented) return;
-
- addClass(nextContent, activeClass);
- removeClass(content, activeClass);
-
- /* istanbul ignore else */
- if (tabContent && hasClass(nextContent, fadeClass)) {
- const nextHeight = nextContent.scrollHeight;
- tabPrivate.set(element, { currentHeight, nextHeight });
-
- addClass(tabContent, collapsingClass);
- tabContent.style.height = `${currentHeight}px`;
- reflow(tabContent);
- [content, nextContent].forEach((c) => {
- removeClass(c, 'overflow-hidden');
- });
- }
-
- if (nextContent && hasClass(nextContent, fadeClass)) {
- setTimeout(() => {
- addClass(nextContent, showClass);
- emulateTransitionEnd(nextContent, () => {
- triggerTabShow(self);
- });
- }, 1);
- } else {
- addClass(nextContent, showClass);
- triggerTabShow(self);
- }
-
- dispatchEvent(tab, hiddenTabEvent);
- }
-
- /**
- * Returns the current active tab and its target content.
- * @param {Tab} self the `Tab` instance
- * @returns {Record<string, any>} the query result
- */
- function getActiveTab(self) {
- const { nav } = self;
-
- const activeTabs = getElementsByClassName(activeClass, nav);
- /** @type {(HTMLElement)=} */
- let tab;
- /* istanbul ignore else */
- if (activeTabs.length === 1
- && !dropdownMenuClasses.some((c) => hasClass(activeTabs[0].parentElement, c))) {
- [tab] = activeTabs;
- } else if (activeTabs.length > 1) {
- tab = activeTabs[activeTabs.length - 1];
- }
- const content = tab ? getTargetElement(tab) : null;
- return { tab, content };
- }
-
- /**
- * Returns a parent dropdown.
- * @param {HTMLElement} element the `Tab` element
- * @returns {HTMLElement?} the parent dropdown
- */
- function getParentDropdown(element) {
- const dropdown = closest(element, `.${dropdownMenuClasses.join(',.')}`);
- return dropdown ? querySelector(`.${dropdownMenuClasses[0]}-toggle`, dropdown) : null;
- }
-
- /**
- * Toggles on/off the `click` event listener.
- * @param {Tab} self the `Tab` instance
- * @param {boolean=} add when `true`, event listener is added
- */
- function toggleTabHandler(self, add) {
- const action = add ? addListener : removeListener;
- action(self.element, mouseclickEvent, tabClickHandler);
- }
-
- // TAB EVENT HANDLER
- // =================
- /**
- * Handles the `click` event listener.
- * @this {HTMLElement}
- * @param {MouseEvent} e the `Event` object
- */
- function tabClickHandler(e) {
- const self = getTabInstance(this);
- /* istanbul ignore next: must filter */
- if (!self) return;
- e.preventDefault();
-
- self.show();
- }
-
- // TAB DEFINITION
- // ==============
- /** Creates a new `Tab` instance. */
- class Tab extends BaseComponent {
- /**
- * @param {HTMLElement | string} target the target element
- */
- constructor(target) {
- super(target);
- // bind
- const self = this;
-
- // initialization element
- const { element } = self;
- const content = getTargetElement(element);
-
- // no point initializing a tab without a corresponding content
- if (!content) return;
-
- const nav = closest(element, '.nav');
- const container = closest(content, '.tab-content');
-
- /** @type {HTMLElement?} */
- self.nav = nav;
- /** @type {HTMLElement} */
- self.content = content;
- /** @type {HTMLElement?} */
- self.tabContent = container;
-
- // event targets
- /** @type {HTMLElement?} */
- self.dropdown = getParentDropdown(element);
-
- // show first Tab instance of none is shown
- // suggested on #432
- const { tab } = getActiveTab(self);
- if (nav && !tab) {
- const firstTab = querySelector(tabSelector, nav);
- const firstTabContent = firstTab && getTargetElement(firstTab);
-
- /* istanbul ignore else */
- if (firstTabContent) {
- addClass(firstTab, activeClass);
- addClass(firstTabContent, showClass);
- addClass(firstTabContent, activeClass);
- setAttribute(element, ariaSelected, 'true');
- }
- }
-
- // add event listener
- toggleTabHandler(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return tabComponent; }
- /* eslint-enable */
-
- // TAB PUBLIC METHODS
- // ==================
- /** Shows the tab to the user. */
- show() {
- const self = this;
- const {
- element, content: nextContent, nav, dropdown,
- } = self;
-
- /* istanbul ignore else */
- if (!(nav && Timer.get(nav)) && !hasClass(element, activeClass)) {
- const { tab, content } = getActiveTab(self);
-
- /* istanbul ignore else */
- if (nav) tabPrivate.set(nav, { tab, content });
-
- // update relatedTarget and dispatch
- hideTabEvent.relatedTarget = element;
-
- dispatchEvent(tab, hideTabEvent);
- if (hideTabEvent.defaultPrevented) return;
-
- addClass(element, activeClass);
- setAttribute(element, ariaSelected, 'true');
-
- const activeDropdown = getParentDropdown(tab);
- if (activeDropdown && hasClass(activeDropdown, activeClass)) {
- removeClass(activeDropdown, activeClass);
- }
-
- /* istanbul ignore else */
- if (nav) {
- const toggleTab = () => {
- removeClass(tab, activeClass);
- setAttribute(tab, ariaSelected, 'false');
- if (dropdown && !hasClass(dropdown, activeClass)) addClass(dropdown, activeClass);
- };
-
- if (hasClass(content, fadeClass) || hasClass(nextContent, fadeClass)) {
- Timer.set(nav, toggleTab, 1);
- } else toggleTab();
- }
-
- removeClass(content, showClass);
- if (hasClass(content, fadeClass)) {
- emulateTransitionEnd(content, () => triggerTabHide(self));
- } else {
- triggerTabHide(self);
- }
- }
- }
-
- /** Removes the `Tab` component from the target element. */
- dispose() {
- toggleTabHandler(this);
- super.dispose();
- }
- }
-
- ObjectAssign(Tab, {
- selector: tabSelector,
- init: tabInitCallback,
- getInstance: getTabInstance,
- });
-
- /** @type {string} */
- const toastString = 'toast';
-
- /** @type {string} */
- const toastComponent = 'Toast';
-
- /* Native JavaScript for Bootstrap 5 | Toast
- -------------------------------------------- */
-
- // TOAST PRIVATE GC
- // ================
- const toastSelector = `.${toastString}`;
- const toastDismissSelector = `[${dataBsDismiss}="${toastString}"]`;
- const toastToggleSelector = `[${dataBsToggle}="${toastString}"]`;
- const showingClass = 'showing';
- /** @deprecated */
- const hideClass = 'hide';
-
- const toastDefaults = {
- animation: true,
- autohide: true,
- delay: 5000,
- };
-
- /**
- * Static method which returns an existing `Toast` instance associated
- * to a target `Element`.
- *
- * @type {BSN.GetInstance<Toast>}
- */
- const getToastInstance = (element) => getInstance(element, toastComponent);
-
- /**
- * A `Toast` initialization callback.
- * @type {BSN.InitCallback<Toast>}
- */
- const toastInitCallback = (element) => new Toast(element);
-
- // TOAST CUSTOM EVENTS
- // ===================
- const showToastEvent = OriginalEvent(`show.bs.${toastString}`);
- const shownToastEvent = OriginalEvent(`shown.bs.${toastString}`);
- const hideToastEvent = OriginalEvent(`hide.bs.${toastString}`);
- const hiddenToastEvent = OriginalEvent(`hidden.bs.${toastString}`);
-
- // TOAST PRIVATE METHODS
- // =====================
- /**
- * Executes after the toast is shown to the user.
- * @param {Toast} self the `Toast` instance
- */
- function showToastComplete(self) {
- const { element, options } = self;
- removeClass(element, showingClass);
- Timer.clear(element, showingClass);
-
- dispatchEvent(element, shownToastEvent);
- /* istanbul ignore else */
- if (options.autohide) {
- Timer.set(element, () => self.hide(), options.delay, toastString);
- }
- }
-
- /**
- * Executes after the toast is hidden to the user.
- * @param {Toast} self the `Toast` instance
- */
- function hideToastComplete(self) {
- const { element } = self;
- removeClass(element, showingClass);
- removeClass(element, showClass);
- addClass(element, hideClass); // B/C
- Timer.clear(element, toastString);
- dispatchEvent(element, hiddenToastEvent);
- }
-
- /**
- * Executes before hiding the toast.
- * @param {Toast} self the `Toast` instance
- */
- function hideToast(self) {
- const { element, options } = self;
- addClass(element, showingClass);
-
- if (options.animation) {
- reflow(element);
- emulateTransitionEnd(element, () => hideToastComplete(self));
- } else {
- hideToastComplete(self);
- }
- }
-
- /**
- * Executes before showing the toast.
- * @param {Toast} self the `Toast` instance
- */
- function showToast(self) {
- const { element, options } = self;
- Timer.set(element, () => {
- removeClass(element, hideClass); // B/C
- reflow(element);
- addClass(element, showClass);
- addClass(element, showingClass);
-
- if (options.animation) {
- emulateTransitionEnd(element, () => showToastComplete(self));
- } else {
- showToastComplete(self);
- }
- }, 17, showingClass);
- }
-
- /**
- * Toggles on/off the `click` event listener.
- * @param {Toast} self the `Toast` instance
- * @param {boolean=} add when `true`, it will add the listener
- */
- function toggleToastHandlers(self, add) {
- const action = add ? addListener : removeListener;
- const {
- element, triggers, dismiss, options,
- } = self;
-
- /* istanbul ignore else */
- if (dismiss) {
- action(dismiss, mouseclickEvent, self.hide);
- }
-
- /* istanbul ignore else */
- if (options.autohide) {
- [focusinEvent, focusoutEvent, mouseenterEvent, mouseleaveEvent]
- .forEach((e) => action(element, e, interactiveToastHandler));
- }
- /* istanbul ignore else */
- if (triggers.length) {
- triggers.forEach((btn) => action(btn, mouseclickEvent, toastClickHandler));
- }
- }
-
- // TOAST EVENT HANDLERS
- // ====================
- /**
- * Executes after the instance has been disposed.
- * @param {Toast} self the `Toast` instance
- */
- function completeDisposeToast(self) {
- Timer.clear(self.element, toastString);
- toggleToastHandlers(self);
- }
-
- /**
- * Handles the `click` event listener for toast.
- * @param {MouseEvent} e the `Event` object
- */
- function toastClickHandler(e) {
- const { target } = e;
-
- const trigger = target && closest(target, toastToggleSelector);
- const element = trigger && getTargetElement(trigger);
- const self = element && getToastInstance(element);
-
- /* istanbul ignore else */
- if (trigger && trigger.tagName === 'A') e.preventDefault();
- self.relatedTarget = trigger;
- self.show();
- }
-
- /**
- * Executes when user interacts with the toast without closing it,
- * usually by hovering or focusing it.
- *
- * @this {HTMLElement}
- * @param {MouseEvent} e the `Toast` instance
- */
- function interactiveToastHandler(e) {
- const element = this;
- const self = getToastInstance(element);
- const { type, relatedTarget } = e;
-
- /* istanbul ignore next: a solid filter is required */
- if (!self || (element === relatedTarget || element.contains(relatedTarget))) return;
-
- if ([mouseenterEvent, focusinEvent].includes(type)) {
- Timer.clear(element, toastString);
- } else {
- Timer.set(element, () => self.hide(), self.options.delay, toastString);
- }
- }
-
- // TOAST DEFINITION
- // ================
- /** Creates a new `Toast` instance. */
- class Toast extends BaseComponent {
- /**
- * @param {HTMLElement | string} target the target `.toast` element
- * @param {BSN.Options.Toast=} config the instance options
- */
- constructor(target, config) {
- super(target, config);
- // bind
- const self = this;
- const { element, options } = self;
-
- // set fadeClass, the options.animation will override the markup
- if (options.animation && !hasClass(element, fadeClass)) addClass(element, fadeClass);
- else if (!options.animation && hasClass(element, fadeClass)) removeClass(element, fadeClass);
-
- // dismiss button
- /** @type {HTMLElement?} */
- self.dismiss = querySelector(toastDismissSelector, element);
-
- // toast can have multiple triggering elements
- /** @type {HTMLElement[]} */
- self.triggers = [...querySelectorAll(toastToggleSelector, getDocument(element))]
- .filter((btn) => getTargetElement(btn) === element);
-
- // bind
- self.show = self.show.bind(self);
- self.hide = self.hide.bind(self);
-
- // add event listener
- toggleToastHandlers(self, true);
- }
-
- /* eslint-disable */
- /**
- * Returns component name string.
- */
- get name() { return toastComponent; }
- /**
- * Returns component default options.
- */
- get defaults() { return toastDefaults; }
- /* eslint-enable */
-
- /**
- * Returns *true* when toast is visible.
- */
- get isShown() { return hasClass(this.element, showClass); }
-
- // TOAST PUBLIC METHODS
- // ====================
- /** Shows the toast. */
- show() {
- const self = this;
- const { element, isShown } = self;
-
- /* istanbul ignore else */
- if (element && !isShown) {
- dispatchEvent(element, showToastEvent);
- if (showToastEvent.defaultPrevented) return;
-
- showToast(self);
- }
- }
-
- /** Hides the toast. */
- hide() {
- const self = this;
- const { element, isShown } = self;
-
- /* istanbul ignore else */
- if (element && isShown) {
- dispatchEvent(element, hideToastEvent);
- if (hideToastEvent.defaultPrevented) return;
- hideToast(self);
- }
- }
-
- /** Removes the `Toast` component from the target element. */
- dispose() {
- const self = this;
- const { element, isShown } = self;
-
- /* istanbul ignore else */
- if (isShown) {
- removeClass(element, showClass);
- }
-
- completeDisposeToast(self);
-
- super.dispose();
- }
- }
-
- ObjectAssign(Toast, {
- selector: toastSelector,
- init: toastInitCallback,
- getInstance: getToastInstance,
- });
-
- /**
- * Check if element matches a CSS selector.
- *
- * @param {HTMLElement} target
- * @param {string} selector
- * @returns {boolean}
- */
- function matches(target, selector) {
- return target.matches(selector);
- }
-
- /** @type {Record<string, any>} */
- const componentsList = {
- Alert,
- Button,
- Carousel,
- Collapse,
- Dropdown,
- Modal,
- Offcanvas,
- Popover,
- ScrollSpy,
- Tab,
- Toast,
- Tooltip,
- };
-
- /**
- * Initialize all matched `Element`s for one component.
- * @param {BSN.InitCallback<any>} callback
- * @param {NodeList | Node[]} collection
- */
- function initComponentDataAPI(callback, collection) {
- [...collection].forEach((x) => callback(x));
- }
-
- /**
- * Remove one component from a target container element or all in the page.
- * @param {string} component the component name
- * @param {ParentNode} context parent `Node`
- */
- function removeComponentDataAPI(component, context) {
- const compData = Data.getAllFor(component);
-
- if (compData) {
- [...compData].forEach((x) => {
- const [element, instance] = x;
- if (context.contains(element)) instance.dispose();
- });
- }
- }
-
- /**
- * Initialize all BSN components for a target container.
- * @param {ParentNode=} context parent `Node`
- */
- function initCallback(context) {
- const lookUp = context && context.nodeName ? context : document;
- const elemCollection = [...getElementsByTagName('*', lookUp)];
-
- ObjectKeys(componentsList).forEach((comp) => {
- const { init, selector } = componentsList[comp];
- initComponentDataAPI(init, elemCollection.filter((item) => matches(item, selector)));
- });
- }
-
- /**
- * Remove all BSN components for a target container.
- * @param {ParentNode=} context parent `Node`
- */
- function removeDataAPI(context) {
- const lookUp = context && context.nodeName ? context : document;
-
- ObjectKeys(componentsList).forEach((comp) => {
- removeComponentDataAPI(comp, lookUp);
- });
- }
-
- // bulk initialize all components
- if (document.body) initCallback();
- else {
- addListener(document, 'DOMContentLoaded', () => initCallback(), { once: true });
- }
-
- const BSN = {
- Alert,
- Button,
- Carousel,
- Collapse,
- Dropdown,
- Modal,
- Offcanvas,
- Popover,
- ScrollSpy,
- Tab,
- Toast,
- Tooltip,
-
- initCallback,
- removeDataAPI,
- Version,
- EventListener: Listener,
- };
-
- return BSN;
-
-}));
diff --git a/src/static/scripts/bootstrap.bundle.js b/src/static/scripts/bootstrap.bundle.js
new file mode 100644
index 00000000..3a02ceb3
--- /dev/null
+++ b/src/static/scripts/bootstrap.bundle.js
@@ -0,0 +1,6313 @@
+/*!
+ * Bootstrap v5.3.1 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrap = factory());
+})(this, (function () { 'use strict';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/data.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+ /**
+ * Constants
+ */
+
+ const elementMap = new Map();
+ const Data = {
+ set(element, key, instance) {
+ if (!elementMap.has(element)) {
+ elementMap.set(element, new Map());
+ }
+ const instanceMap = elementMap.get(element);
+
+ // make it clear we only want one instance per element
+ // can be removed later when multiple key/instances are fine to be used
+ if (!instanceMap.has(key) && instanceMap.size !== 0) {
+ // eslint-disable-next-line no-console
+ console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);
+ return;
+ }
+ instanceMap.set(key, instance);
+ },
+ get(element, key) {
+ if (elementMap.has(element)) {
+ return elementMap.get(element).get(key) || null;
+ }
+ return null;
+ },
+ remove(element, key) {
+ if (!elementMap.has(element)) {
+ return;
+ }
+ const instanceMap = elementMap.get(element);
+ instanceMap.delete(key);
+
+ // free up element references if there are no instances left for an element
+ if (instanceMap.size === 0) {
+ elementMap.delete(element);
+ }
+ }
+ };
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/index.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+ const MAX_UID = 1000000;
+ const MILLISECONDS_MULTIPLIER = 1000;
+ const TRANSITION_END = 'transitionend';
+
+ /**
+ * Properly escape IDs selectors to handle weird IDs
+ * @param {string} selector
+ * @returns {string}
+ */
+ const parseSelector = selector => {
+ if (selector && window.CSS && window.CSS.escape) {
+ // document.querySelector needs escaping to handle IDs (html5+) containing for instance /
+ selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`);
+ }
+ return selector;
+ };
+
+ // Shout-out Angus Croll (https://goo.gl/pxwQGp)
+ const toType = object => {
+ if (object === null || object === undefined) {
+ return `${object}`;
+ }
+ return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase();
+ };
+
+ /**
+ * Public Util API
+ */
+
+ const getUID = prefix => {
+ do {
+ prefix += Math.floor(Math.random() * MAX_UID);
+ } while (document.getElementById(prefix));
+ return prefix;
+ };
+ const getTransitionDurationFromElement = element => {
+ if (!element) {
+ return 0;
+ }
+
+ // Get transition-duration of the element
+ let {
+ transitionDuration,
+ transitionDelay
+ } = window.getComputedStyle(element);
+ const floatTransitionDuration = Number.parseFloat(transitionDuration);
+ const floatTransitionDelay = Number.parseFloat(transitionDelay);
+
+ // Return 0 if element or transition duration is not found
+ if (!floatTransitionDuration && !floatTransitionDelay) {
+ return 0;
+ }
+
+ // If multiple durations are defined, take the first
+ transitionDuration = transitionDuration.split(',')[0];
+ transitionDelay = transitionDelay.split(',')[0];
+ return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
+ };
+ const triggerTransitionEnd = element => {
+ element.dispatchEvent(new Event(TRANSITION_END));
+ };
+ const isElement$1 = object => {
+ if (!object || typeof object !== 'object') {
+ return false;
+ }
+ if (typeof object.jquery !== 'undefined') {
+ object = object[0];
+ }
+ return typeof object.nodeType !== 'undefined';
+ };
+ const getElement = object => {
+ // it's a jQuery object or a node element
+ if (isElement$1(object)) {
+ return object.jquery ? object[0] : object;
+ }
+ if (typeof object === 'string' && object.length > 0) {
+ return document.querySelector(parseSelector(object));
+ }
+ return null;
+ };
+ const isVisible = element => {
+ if (!isElement$1(element) || element.getClientRects().length === 0) {
+ return false;
+ }
+ const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';
+ // Handle `details` element as its content may falsie appear visible when it is closed
+ const closedDetails = element.closest('details:not([open])');
+ if (!closedDetails) {
+ return elementIsVisible;
+ }
+ if (closedDetails !== element) {
+ const summary = element.closest('summary');
+ if (summary && summary.parentNode !== closedDetails) {
+ return false;
+ }
+ if (summary === null) {
+ return false;
+ }
+ }
+ return elementIsVisible;
+ };
+ const isDisabled = element => {
+ if (!element || element.nodeType !== Node.ELEMENT_NODE) {
+ return true;
+ }
+ if (element.classList.contains('disabled')) {
+ return true;
+ }
+ if (typeof element.disabled !== 'undefined') {
+ return element.disabled;
+ }
+ return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
+ };
+ const findShadowRoot = element => {
+ if (!document.documentElement.attachShadow) {
+ return null;
+ }
+
+ // Can find the shadow root otherwise it'll return the document
+ if (typeof element.getRootNode === 'function') {
+ const root = element.getRootNode();
+ return root instanceof ShadowRoot ? root : null;
+ }
+ if (element instanceof ShadowRoot) {
+ return element;
+ }
+
+ // when we don't find a shadow root
+ if (!element.parentNode) {
+ return null;
+ }
+ return findShadowRoot(element.parentNode);
+ };
+ const noop = () => {};
+
+ /**
+ * Trick to restart an element's animation
+ *
+ * @param {HTMLElement} element
+ * @return void
+ *
+ * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
+ */
+ const reflow = element => {
+ element.offsetHeight; // eslint-disable-line no-unused-expressions
+ };
+
+ const getjQuery = () => {
+ if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
+ return window.jQuery;
+ }
+ return null;
+ };
+ const DOMContentLoadedCallbacks = [];
+ const onDOMContentLoaded = callback => {
+ if (document.readyState === 'loading') {
+ // add listener on the first call when the document is in loading state
+ if (!DOMContentLoadedCallbacks.length) {
+ document.addEventListener('DOMContentLoaded', () => {
+ for (const callback of DOMContentLoadedCallbacks) {
+ callback();
+ }
+ });
+ }
+ DOMContentLoadedCallbacks.push(callback);
+ } else {
+ callback();
+ }
+ };
+ const isRTL = () => document.documentElement.dir === 'rtl';
+ const defineJQueryPlugin = plugin => {
+ onDOMContentLoaded(() => {
+ const $ = getjQuery();
+ /* istanbul ignore if */
+ if ($) {
+ const name = plugin.NAME;
+ const JQUERY_NO_CONFLICT = $.fn[name];
+ $.fn[name] = plugin.jQueryInterface;
+ $.fn[name].Constructor = plugin;
+ $.fn[name].noConflict = () => {
+ $.fn[name] = JQUERY_NO_CONFLICT;
+ return plugin.jQueryInterface;
+ };
+ }
+ });
+ };
+ const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
+ return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;
+ };
+ const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
+ if (!waitForTransition) {
+ execute(callback);
+ return;
+ }
+ const durationPadding = 5;
+ const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
+ let called = false;
+ const handler = ({
+ target
+ }) => {
+ if (target !== transitionElement) {
+ return;
+ }
+ called = true;
+ transitionElement.removeEventListener(TRANSITION_END, handler);
+ execute(callback);
+ };
+ transitionElement.addEventListener(TRANSITION_END, handler);
+ setTimeout(() => {
+ if (!called) {
+ triggerTransitionEnd(transitionElement);
+ }
+ }, emulatedDuration);
+ };
+
+ /**
+ * Return the previous/next element of a list.
+ *
+ * @param {array} list The list of elements
+ * @param activeElement The active element
+ * @param shouldGetNext Choose to get next or previous element
+ * @param isCycleAllowed
+ * @return {Element|elem} The proper element
+ */
+ const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
+ const listLength = list.length;
+ let index = list.indexOf(activeElement);
+
+ // if the element does not exist in the list return an element
+ // depending on the direction and if cycle is allowed
+ if (index === -1) {
+ return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];
+ }
+ index += shouldGetNext ? 1 : -1;
+ if (isCycleAllowed) {
+ index = (index + listLength) % listLength;
+ }
+ return list[Math.max(0, Math.min(index, listLength - 1))];
+ };
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/event-handler.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const namespaceRegex = /[^.]*(?=\..*)\.|.*/;
+ const stripNameRegex = /\..*/;
+ const stripUidRegex = /::\d+$/;
+ const eventRegistry = {}; // Events storage
+ let uidEvent = 1;
+ const customEvents = {
+ mouseenter: 'mouseover',
+ mouseleave: 'mouseout'
+ };
+ 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']);
+
+ /**
+ * Private methods
+ */
+
+ function makeEventUid(element, uid) {
+ return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++;
+ }
+ function getElementEvents(element) {
+ const uid = makeEventUid(element);
+ element.uidEvent = uid;
+ eventRegistry[uid] = eventRegistry[uid] || {};
+ return eventRegistry[uid];
+ }
+ function bootstrapHandler(element, fn) {
+ return function handler(event) {
+ hydrateObj(event, {
+ delegateTarget: element
+ });
+ if (handler.oneOff) {
+ EventHandler.off(element, event.type, fn);
+ }
+ return fn.apply(element, [event]);
+ };
+ }
+ function bootstrapDelegationHandler(element, selector, fn) {
+ return function handler(event) {
+ const domElements = element.querySelectorAll(selector);
+ for (let {
+ target
+ } = event; target && target !== this; target = target.parentNode) {
+ for (const domElement of domElements) {
+ if (domElement !== target) {
+ continue;
+ }
+ hydrateObj(event, {
+ delegateTarget: target
+ });
+ if (handler.oneOff) {
+ EventHandler.off(element, event.type, selector, fn);
+ }
+ return fn.apply(target, [event]);
+ }
+ }
+ };
+ }
+ function findHandler(events, callable, delegationSelector = null) {
+ return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector);
+ }
+ function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
+ const isDelegated = typeof handler === 'string';
+ // TODO: tooltip passes `false` instead of selector, so we need to check
+ const callable = isDelegated ? delegationFunction : handler || delegationFunction;
+ let typeEvent = getTypeEvent(originalTypeEvent);
+ if (!nativeEvents.has(typeEvent)) {
+ typeEvent = originalTypeEvent;
+ }
+ return [isDelegated, callable, typeEvent];
+ }
+ function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
+ if (typeof originalTypeEvent !== 'string' || !element) {
+ return;
+ }
+ let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);
+
+ // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
+ // this prevents the handler from being dispatched the same way as mouseover or mouseout does
+ if (originalTypeEvent in customEvents) {
+ const wrapFunction = fn => {
+ return function (event) {
+ if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) {
+ return fn.call(this, event);
+ }
+ };
+ };
+ callable = wrapFunction(callable);
+ }
+ const events = getElementEvents(element);
+ const handlers = events[typeEvent] || (events[typeEvent] = {});
+ const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);
+ if (previousFunction) {
+ previousFunction.oneOff = previousFunction.oneOff && oneOff;
+ return;
+ }
+ const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''));
+ const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable);
+ fn.delegationSelector = isDelegated ? handler : null;
+ fn.callable = callable;
+ fn.oneOff = oneOff;
+ fn.uidEvent = uid;
+ handlers[uid] = fn;
+ element.addEventListener(typeEvent, fn, isDelegated);
+ }
+ function removeHandler(element, events, typeEvent, handler, delegationSelector) {
+ const fn = findHandler(events[typeEvent], handler, delegationSelector);
+ if (!fn) {
+ return;
+ }
+ element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));
+ delete events[typeEvent][fn.uidEvent];
+ }
+ function removeNamespacedHandlers(element, events, typeEvent, namespace) {
+ const storeElementEvent = events[typeEvent] || {};
+ for (const [handlerKey, event] of Object.entries(storeElementEvent)) {
+ if (handlerKey.includes(namespace)) {
+ removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
+ }
+ }
+ }
+ function getTypeEvent(event) {
+ // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
+ event = event.replace(stripNameRegex, '');
+ return customEvents[event] || event;
+ }
+ const EventHandler = {
+ on(element, event, handler, delegationFunction) {
+ addHandler(element, event, handler, delegationFunction, false);
+ },
+ one(element, event, handler, delegationFunction) {
+ addHandler(element, event, handler, delegationFunction, true);
+ },
+ off(element, originalTypeEvent, handler, delegationFunction) {
+ if (typeof originalTypeEvent !== 'string' || !element) {
+ return;
+ }
+ const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);
+ const inNamespace = typeEvent !== originalTypeEvent;
+ const events = getElementEvents(element);
+ const storeElementEvent = events[typeEvent] || {};
+ const isNamespace = originalTypeEvent.startsWith('.');
+ if (typeof callable !== 'undefined') {
+ // Simplest case: handler is passed, remove that listener ONLY.
+ if (!Object.keys(storeElementEvent).length) {
+ return;
+ }
+ removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);
+ return;
+ }
+ if (isNamespace) {
+ for (const elementEvent of Object.keys(events)) {
+ removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));
+ }
+ }
+ for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {
+ const handlerKey = keyHandlers.replace(stripUidRegex, '');
+ if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
+ removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
+ }
+ }
+ },
+ trigger(element, event, args) {
+ if (typeof event !== 'string' || !element) {
+ return null;
+ }
+ const $ = getjQuery();
+ const typeEvent = getTypeEvent(event);
+ const inNamespace = event !== typeEvent;
+ let jQueryEvent = null;
+ let bubbles = true;
+ let nativeDispatch = true;
+ let defaultPrevented = false;
+ if (inNamespace && $) {
+ jQueryEvent = $.Event(event, args);
+ $(element).trigger(jQueryEvent);
+ bubbles = !jQueryEvent.isPropagationStopped();
+ nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
+ defaultPrevented = jQueryEvent.isDefaultPrevented();
+ }
+ const evt = hydrateObj(new Event(event, {
+ bubbles,
+ cancelable: true
+ }), args);
+ if (defaultPrevented) {
+ evt.preventDefault();
+ }
+ if (nativeDispatch) {
+ element.dispatchEvent(evt);
+ }
+ if (evt.defaultPrevented && jQueryEvent) {
+ jQueryEvent.preventDefault();
+ }
+ return evt;
+ }
+ };
+ function hydrateObj(obj, meta = {}) {
+ for (const [key, value] of Object.entries(meta)) {
+ try {
+ obj[key] = value;
+ } catch (_unused) {
+ Object.defineProperty(obj, key, {
+ configurable: true,
+ get() {
+ return value;
+ }
+ });
+ }
+ }
+ return obj;
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/manipulator.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+ function normalizeData(value) {
+ if (value === 'true') {
+ return true;
+ }
+ if (value === 'false') {
+ return false;
+ }
+ if (value === Number(value).toString()) {
+ return Number(value);
+ }
+ if (value === '' || value === 'null') {
+ return null;
+ }
+ if (typeof value !== 'string') {
+ return value;
+ }
+ try {
+ return JSON.parse(decodeURIComponent(value));
+ } catch (_unused) {
+ return value;
+ }
+ }
+ function normalizeDataKey(key) {
+ return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);
+ }
+ const Manipulator = {
+ setDataAttribute(element, key, value) {
+ element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);
+ },
+ removeDataAttribute(element, key) {
+ element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);
+ },
+ getDataAttributes(element) {
+ if (!element) {
+ return {};
+ }
+ const attributes = {};
+ const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));
+ for (const key of bsKeys) {
+ let pureKey = key.replace(/^bs/, '');
+ pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);
+ attributes[pureKey] = normalizeData(element.dataset[key]);
+ }
+ return attributes;
+ },
+ getDataAttribute(element, key) {
+ return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));
+ }
+ };
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/config.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Class definition
+ */
+
+ class Config {
+ // Getters
+ static get Default() {
+ return {};
+ }
+ static get DefaultType() {
+ return {};
+ }
+ static get NAME() {
+ throw new Error('You have to implement the static method "NAME", for each component!');
+ }
+ _getConfig(config) {
+ config = this._mergeConfigObj(config);
+ config = this._configAfterMerge(config);
+ this._typeCheckConfig(config);
+ return config;
+ }
+ _configAfterMerge(config) {
+ return config;
+ }
+ _mergeConfigObj(config, element) {
+ const jsonConfig = isElement$1(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse
+
+ return {
+ ...this.constructor.Default,
+ ...(typeof jsonConfig === 'object' ? jsonConfig : {}),
+ ...(isElement$1(element) ? Manipulator.getDataAttributes(element) : {}),
+ ...(typeof config === 'object' ? config : {})
+ };
+ }
+ _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
+ for (const [property, expectedTypes] of Object.entries(configTypes)) {
+ const value = config[property];
+ const valueType = isElement$1(value) ? 'element' : toType(value);
+ if (!new RegExp(expectedTypes).test(valueType)) {
+ throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
+ }
+ }
+ }
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap base-component.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const VERSION = '5.3.1';
+
+ /**
+ * Class definition
+ */
+
+ class BaseComponent extends Config {
+ constructor(element, config) {
+ super();
+ element = getElement(element);
+ if (!element) {
+ return;
+ }
+ this._element = element;
+ this._config = this._getConfig(config);
+ Data.set(this._element, this.constructor.DATA_KEY, this);
+ }
+
+ // Public
+ dispose() {
+ Data.remove(this._element, this.constructor.DATA_KEY);
+ EventHandler.off(this._element, this.constructor.EVENT_KEY);
+ for (const propertyName of Object.getOwnPropertyNames(this)) {
+ this[propertyName] = null;
+ }
+ }
+ _queueCallback(callback, element, isAnimated = true) {
+ executeAfterTransition(callback, element, isAnimated);
+ }
+ _getConfig(config) {
+ config = this._mergeConfigObj(config, this._element);
+ config = this._configAfterMerge(config);
+ this._typeCheckConfig(config);
+ return config;
+ }
+
+ // Static
+ static getInstance(element) {
+ return Data.get(getElement(element), this.DATA_KEY);
+ }
+ static getOrCreateInstance(element, config = {}) {
+ return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);
+ }
+ static get VERSION() {
+ return VERSION;
+ }
+ static get DATA_KEY() {
+ return `bs.${this.NAME}`;
+ }
+ static get EVENT_KEY() {
+ return `.${this.DATA_KEY}`;
+ }
+ static eventName(name) {
+ return `${name}${this.EVENT_KEY}`;
+ }
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/selector-engine.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+ const getSelector = element => {
+ let selector = element.getAttribute('data-bs-target');
+ if (!selector || selector === '#') {
+ let hrefAttribute = element.getAttribute('href');
+
+ // The only valid content that could double as a selector are IDs or classes,
+ // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
+ // `document.querySelector` will rightfully complain it is invalid.
+ // See https://github.com/twbs/bootstrap/issues/32273
+ if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {
+ return null;
+ }
+
+ // Just in case some CMS puts out a full URL with the anchor appended
+ if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
+ hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
+ }
+ selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;
+ }
+ return parseSelector(selector);
+ };
+ const SelectorEngine = {
+ find(selector, element = document.documentElement) {
+ return [].concat(...Element.prototype.querySelectorAll.call(element, selector));
+ },
+ findOne(selector, element = document.documentElement) {
+ return Element.prototype.querySelector.call(element, selector);
+ },
+ children(element, selector) {
+ return [].concat(...element.children).filter(child => child.matches(selector));
+ },
+ parents(element, selector) {
+ const parents = [];
+ let ancestor = element.parentNode.closest(selector);
+ while (ancestor) {
+ parents.push(ancestor);
+ ancestor = ancestor.parentNode.closest(selector);
+ }
+ return parents;
+ },
+ prev(element, selector) {
+ let previous = element.previousElementSibling;
+ while (previous) {
+ if (previous.matches(selector)) {
+ return [previous];
+ }
+ previous = previous.previousElementSibling;
+ }
+ return [];
+ },
+ // TODO: this is now unused; remove later along with prev()
+ next(element, selector) {
+ let next = element.nextElementSibling;
+ while (next) {
+ if (next.matches(selector)) {
+ return [next];
+ }
+ next = next.nextElementSibling;
+ }
+ return [];
+ },
+ focusableChildren(element) {
+ const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(',');
+ return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el));
+ },
+ getSelectorFromElement(element) {
+ const selector = getSelector(element);
+ if (selector) {
+ return SelectorEngine.findOne(selector) ? selector : null;
+ }
+ return null;
+ },
+ getElementFromSelector(element) {
+ const selector = getSelector(element);
+ return selector ? SelectorEngine.findOne(selector) : null;
+ },
+ getMultipleElementsFromSelector(element) {
+ const selector = getSelector(element);
+ return selector ? SelectorEngine.find(selector) : [];
+ }
+ };
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/component-functions.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+ const enableDismissTrigger = (component, method = 'hide') => {
+ const clickEvent = `click.dismiss${component.EVENT_KEY}`;
+ const name = component.NAME;
+ EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
+ if (['A', 'AREA'].includes(this.tagName)) {
+ event.preventDefault();
+ }
+ if (isDisabled(this)) {
+ return;
+ }
+ const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`);
+ const instance = component.getOrCreateInstance(target);
+
+ // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
+ instance[method]();
+ });
+ };
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap alert.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$f = 'alert';
+ const DATA_KEY$a = 'bs.alert';
+ const EVENT_KEY$b = `.${DATA_KEY$a}`;
+ const EVENT_CLOSE = `close${EVENT_KEY$b}`;
+ const EVENT_CLOSED = `closed${EVENT_KEY$b}`;
+ const CLASS_NAME_FADE$5 = 'fade';
+ const CLASS_NAME_SHOW$8 = 'show';
+
+ /**
+ * Class definition
+ */
+
+ class Alert extends BaseComponent {
+ // Getters
+ static get NAME() {
+ return NAME$f;
+ }
+
+ // Public
+ close() {
+ const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);
+ if (closeEvent.defaultPrevented) {
+ return;
+ }
+ this._element.classList.remove(CLASS_NAME_SHOW$8);
+ const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5);
+ this._queueCallback(() => this._destroyElement(), this._element, isAnimated);
+ }
+
+ // Private
+ _destroyElement() {
+ this._element.remove();
+ EventHandler.trigger(this._element, EVENT_CLOSED);
+ this.dispose();
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Alert.getOrCreateInstance(this);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config](this);
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ enableDismissTrigger(Alert, 'close');
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Alert);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap button.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$e = 'button';
+ const DATA_KEY$9 = 'bs.button';
+ const EVENT_KEY$a = `.${DATA_KEY$9}`;
+ const DATA_API_KEY$6 = '.data-api';
+ const CLASS_NAME_ACTIVE$3 = 'active';
+ const SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle="button"]';
+ const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`;
+
+ /**
+ * Class definition
+ */
+
+ class Button extends BaseComponent {
+ // Getters
+ static get NAME() {
+ return NAME$e;
+ }
+
+ // Public
+ toggle() {
+ // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method
+ this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3));
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Button.getOrCreateInstance(this);
+ if (config === 'toggle') {
+ data[config]();
+ }
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => {
+ event.preventDefault();
+ const button = event.target.closest(SELECTOR_DATA_TOGGLE$5);
+ const data = Button.getOrCreateInstance(button);
+ data.toggle();
+ });
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Button);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/swipe.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$d = 'swipe';
+ const EVENT_KEY$9 = '.bs.swipe';
+ const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`;
+ const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`;
+ const EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`;
+ const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`;
+ const EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`;
+ const POINTER_TYPE_TOUCH = 'touch';
+ const POINTER_TYPE_PEN = 'pen';
+ const CLASS_NAME_POINTER_EVENT = 'pointer-event';
+ const SWIPE_THRESHOLD = 40;
+ const Default$c = {
+ endCallback: null,
+ leftCallback: null,
+ rightCallback: null
+ };
+ const DefaultType$c = {
+ endCallback: '(function|null)',
+ leftCallback: '(function|null)',
+ rightCallback: '(function|null)'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Swipe extends Config {
+ constructor(element, config) {
+ super();
+ this._element = element;
+ if (!element || !Swipe.isSupported()) {
+ return;
+ }
+ this._config = this._getConfig(config);
+ this._deltaX = 0;
+ this._supportPointerEvents = Boolean(window.PointerEvent);
+ this._initEvents();
+ }
+
+ // Getters
+ static get Default() {
+ return Default$c;
+ }
+ static get DefaultType() {
+ return DefaultType$c;
+ }
+ static get NAME() {
+ return NAME$d;
+ }
+
+ // Public
+ dispose() {
+ EventHandler.off(this._element, EVENT_KEY$9);
+ }
+
+ // Private
+ _start(event) {
+ if (!this._supportPointerEvents) {
+ this._deltaX = event.touches[0].clientX;
+ return;
+ }
+ if (this._eventIsPointerPenTouch(event)) {
+ this._deltaX = event.clientX;
+ }
+ }
+ _end(event) {
+ if (this._eventIsPointerPenTouch(event)) {
+ this._deltaX = event.clientX - this._deltaX;
+ }
+ this._handleSwipe();
+ execute(this._config.endCallback);
+ }
+ _move(event) {
+ this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;
+ }
+ _handleSwipe() {
+ const absDeltaX = Math.abs(this._deltaX);
+ if (absDeltaX <= SWIPE_THRESHOLD) {
+ return;
+ }
+ const direction = absDeltaX / this._deltaX;
+ this._deltaX = 0;
+ if (!direction) {
+ return;
+ }
+ execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);
+ }
+ _initEvents() {
+ if (this._supportPointerEvents) {
+ EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));
+ EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));
+ this._element.classList.add(CLASS_NAME_POINTER_EVENT);
+ } else {
+ EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));
+ EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));
+ EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));
+ }
+ }
+ _eventIsPointerPenTouch(event) {
+ return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);
+ }
+
+ // Static
+ static isSupported() {
+ return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
+ }
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap carousel.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$c = 'carousel';
+ const DATA_KEY$8 = 'bs.carousel';
+ const EVENT_KEY$8 = `.${DATA_KEY$8}`;
+ const DATA_API_KEY$5 = '.data-api';
+ const ARROW_LEFT_KEY$1 = 'ArrowLeft';
+ const ARROW_RIGHT_KEY$1 = 'ArrowRight';
+ const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
+
+ const ORDER_NEXT = 'next';
+ const ORDER_PREV = 'prev';
+ const DIRECTION_LEFT = 'left';
+ const DIRECTION_RIGHT = 'right';
+ const EVENT_SLIDE = `slide${EVENT_KEY$8}`;
+ const EVENT_SLID = `slid${EVENT_KEY$8}`;
+ const EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`;
+ const EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`;
+ const EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`;
+ const EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`;
+ const EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`;
+ const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`;
+ const CLASS_NAME_CAROUSEL = 'carousel';
+ const CLASS_NAME_ACTIVE$2 = 'active';
+ const CLASS_NAME_SLIDE = 'slide';
+ const CLASS_NAME_END = 'carousel-item-end';
+ const CLASS_NAME_START = 'carousel-item-start';
+ const CLASS_NAME_NEXT = 'carousel-item-next';
+ const CLASS_NAME_PREV = 'carousel-item-prev';
+ const SELECTOR_ACTIVE = '.active';
+ const SELECTOR_ITEM = '.carousel-item';
+ const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;
+ const SELECTOR_ITEM_IMG = '.carousel-item img';
+ const SELECTOR_INDICATORS = '.carousel-indicators';
+ const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';
+ const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]';
+ const KEY_TO_DIRECTION = {
+ [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT,
+ [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT
+ };
+ const Default$b = {
+ interval: 5000,
+ keyboard: true,
+ pause: 'hover',
+ ride: false,
+ touch: true,
+ wrap: true
+ };
+ const DefaultType$b = {
+ interval: '(number|boolean)',
+ // TODO:v6 remove boolean support
+ keyboard: 'boolean',
+ pause: '(string|boolean)',
+ ride: '(boolean|string)',
+ touch: 'boolean',
+ wrap: 'boolean'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Carousel extends BaseComponent {
+ constructor(element, config) {
+ super(element, config);
+ this._interval = null;
+ this._activeElement = null;
+ this._isSliding = false;
+ this.touchTimeout = null;
+ this._swipeHelper = null;
+ this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);
+ this._addEventListeners();
+ if (this._config.ride === CLASS_NAME_CAROUSEL) {
+ this.cycle();
+ }
+ }
+
+ // Getters
+ static get Default() {
+ return Default$b;
+ }
+ static get DefaultType() {
+ return DefaultType$b;
+ }
+ static get NAME() {
+ return NAME$c;
+ }
+
+ // Public
+ next() {
+ this._slide(ORDER_NEXT);
+ }
+ nextWhenVisible() {
+ // FIXME TODO use `document.visibilityState`
+ // Don't call next when the page isn't visible
+ // or the carousel or its parent isn't visible
+ if (!document.hidden && isVisible(this._element)) {
+ this.next();
+ }
+ }
+ prev() {
+ this._slide(ORDER_PREV);
+ }
+ pause() {
+ if (this._isSliding) {
+ triggerTransitionEnd(this._element);
+ }
+ this._clearInterval();
+ }
+ cycle() {
+ this._clearInterval();
+ this._updateInterval();
+ this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);
+ }
+ _maybeEnableCycle() {
+ if (!this._config.ride) {
+ return;
+ }
+ if (this._isSliding) {
+ EventHandler.one(this._element, EVENT_SLID, () => this.cycle());
+ return;
+ }
+ this.cycle();
+ }
+ to(index) {
+ const items = this._getItems();
+ if (index > items.length - 1 || index < 0) {
+ return;
+ }
+ if (this._isSliding) {
+ EventHandler.one(this._element, EVENT_SLID, () => this.to(index));
+ return;
+ }
+ const activeIndex = this._getItemIndex(this._getActive());
+ if (activeIndex === index) {
+ return;
+ }
+ const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;
+ this._slide(order, items[index]);
+ }
+ dispose() {
+ if (this._swipeHelper) {
+ this._swipeHelper.dispose();
+ }
+ super.dispose();
+ }
+
+ // Private
+ _configAfterMerge(config) {
+ config.defaultInterval = config.interval;
+ return config;
+ }
+ _addEventListeners() {
+ if (this._config.keyboard) {
+ EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event));
+ }
+ if (this._config.pause === 'hover') {
+ EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause());
+ EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle());
+ }
+ if (this._config.touch && Swipe.isSupported()) {
+ this._addTouchEventListeners();
+ }
+ }
+ _addTouchEventListeners() {
+ for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {
+ EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());
+ }
+ const endCallBack = () => {
+ if (this._config.pause !== 'hover') {
+ return;
+ }
+
+ // If it's a touch-enabled device, mouseenter/leave are fired as
+ // part of the mouse compatibility events on first tap - the carousel
+ // would stop cycling until user tapped out of it;
+ // here, we listen for touchend, explicitly pause the carousel
+ // (as if it's the second time we tap on it, mouseenter compat event
+ // is NOT fired) and after a timeout (to allow for mouse compatibility
+ // events to fire) we explicitly restart cycling
+
+ this.pause();
+ if (this.touchTimeout) {
+ clearTimeout(this.touchTimeout);
+ }
+ this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);
+ };
+ const swipeConfig = {
+ leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),
+ rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),
+ endCallback: endCallBack
+ };
+ this._swipeHelper = new Swipe(this._element, swipeConfig);
+ }
+ _keydown(event) {
+ if (/input|textarea/i.test(event.target.tagName)) {
+ return;
+ }
+ const direction = KEY_TO_DIRECTION[event.key];
+ if (direction) {
+ event.preventDefault();
+ this._slide(this._directionToOrder(direction));
+ }
+ }
+ _getItemIndex(element) {
+ return this._getItems().indexOf(element);
+ }
+ _setActiveIndicatorElement(index) {
+ if (!this._indicatorsElement) {
+ return;
+ }
+ const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);
+ activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2);
+ activeIndicator.removeAttribute('aria-current');
+ const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement);
+ if (newActiveIndicator) {
+ newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2);
+ newActiveIndicator.setAttribute('aria-current', 'true');
+ }
+ }
+ _updateInterval() {
+ const element = this._activeElement || this._getActive();
+ if (!element) {
+ return;
+ }
+ const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);
+ this._config.interval = elementInterval || this._config.defaultInterval;
+ }
+ _slide(order, element = null) {
+ if (this._isSliding) {
+ return;
+ }
+ const activeElement = this._getActive();
+ const isNext = order === ORDER_NEXT;
+ const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);
+ if (nextElement === activeElement) {
+ return;
+ }
+ const nextElementIndex = this._getItemIndex(nextElement);
+ const triggerEvent = eventName => {
+ return EventHandler.trigger(this._element, eventName, {
+ relatedTarget: nextElement,
+ direction: this._orderToDirection(order),
+ from: this._getItemIndex(activeElement),
+ to: nextElementIndex
+ });
+ };
+ const slideEvent = triggerEvent(EVENT_SLIDE);
+ if (slideEvent.defaultPrevented) {
+ return;
+ }
+ if (!activeElement || !nextElement) {
+ // Some weirdness is happening, so we bail
+ // TODO: change tests that use empty divs to avoid this check
+ return;
+ }
+ const isCycling = Boolean(this._interval);
+ this.pause();
+ this._isSliding = true;
+ this._setActiveIndicatorElement(nextElementIndex);
+ this._activeElement = nextElement;
+ const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;
+ const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;
+ nextElement.classList.add(orderClassName);
+ reflow(nextElement);
+ activeElement.classList.add(directionalClassName);
+ nextElement.classList.add(directionalClassName);
+ const completeCallBack = () => {
+ nextElement.classList.remove(directionalClassName, orderClassName);
+ nextElement.classList.add(CLASS_NAME_ACTIVE$2);
+ activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName);
+ this._isSliding = false;
+ triggerEvent(EVENT_SLID);
+ };
+ this._queueCallback(completeCallBack, activeElement, this._isAnimated());
+ if (isCycling) {
+ this.cycle();
+ }
+ }
+ _isAnimated() {
+ return this._element.classList.contains(CLASS_NAME_SLIDE);
+ }
+ _getActive() {
+ return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);
+ }
+ _getItems() {
+ return SelectorEngine.find(SELECTOR_ITEM, this._element);
+ }
+ _clearInterval() {
+ if (this._interval) {
+ clearInterval(this._interval);
+ this._interval = null;
+ }
+ }
+ _directionToOrder(direction) {
+ if (isRTL()) {
+ return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;
+ }
+ return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;
+ }
+ _orderToDirection(order) {
+ if (isRTL()) {
+ return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;
+ }
+ return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Carousel.getOrCreateInstance(this, config);
+ if (typeof config === 'number') {
+ data.to(config);
+ return;
+ }
+ if (typeof config === 'string') {
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config]();
+ }
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) {
+ const target = SelectorEngine.getElementFromSelector(this);
+ if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
+ return;
+ }
+ event.preventDefault();
+ const carousel = Carousel.getOrCreateInstance(target);
+ const slideIndex = this.getAttribute('data-bs-slide-to');
+ if (slideIndex) {
+ carousel.to(slideIndex);
+ carousel._maybeEnableCycle();
+ return;
+ }
+ if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
+ carousel.next();
+ carousel._maybeEnableCycle();
+ return;
+ }
+ carousel.prev();
+ carousel._maybeEnableCycle();
+ });
+ EventHandler.on(window, EVENT_LOAD_DATA_API$3, () => {
+ const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);
+ for (const carousel of carousels) {
+ Carousel.getOrCreateInstance(carousel);
+ }
+ });
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Carousel);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap collapse.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$b = 'collapse';
+ const DATA_KEY$7 = 'bs.collapse';
+ const EVENT_KEY$7 = `.${DATA_KEY$7}`;
+ const DATA_API_KEY$4 = '.data-api';
+ const EVENT_SHOW$6 = `show${EVENT_KEY$7}`;
+ const EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`;
+ const EVENT_HIDE$6 = `hide${EVENT_KEY$7}`;
+ const EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`;
+ const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`;
+ const CLASS_NAME_SHOW$7 = 'show';
+ const CLASS_NAME_COLLAPSE = 'collapse';
+ const CLASS_NAME_COLLAPSING = 'collapsing';
+ const CLASS_NAME_COLLAPSED = 'collapsed';
+ const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;
+ const CLASS_NAME_HORIZONTAL = 'collapse-horizontal';
+ const WIDTH = 'width';
+ const HEIGHT = 'height';
+ const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';
+ const SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle="collapse"]';
+ const Default$a = {
+ parent: null,
+ toggle: true
+ };
+ const DefaultType$a = {
+ parent: '(null|element)',
+ toggle: 'boolean'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Collapse extends BaseComponent {
+ constructor(element, config) {
+ super(element, config);
+ this._isTransitioning = false;
+ this._triggerArray = [];
+ const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4);
+ for (const elem of toggleList) {
+ const selector = SelectorEngine.getSelectorFromElement(elem);
+ const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element);
+ if (selector !== null && filterElement.length) {
+ this._triggerArray.push(elem);
+ }
+ }
+ this._initializeChildren();
+ if (!this._config.parent) {
+ this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());
+ }
+ if (this._config.toggle) {
+ this.toggle();
+ }
+ }
+
+ // Getters
+ static get Default() {
+ return Default$a;
+ }
+ static get DefaultType() {
+ return DefaultType$a;
+ }
+ static get NAME() {
+ return NAME$b;
+ }
+
+ // Public
+ toggle() {
+ if (this._isShown()) {
+ this.hide();
+ } else {
+ this.show();
+ }
+ }
+ show() {
+ if (this._isTransitioning || this._isShown()) {
+ return;
+ }
+ let activeChildren = [];
+
+ // find active children
+ if (this._config.parent) {
+ activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, {
+ toggle: false
+ }));
+ }
+ if (activeChildren.length && activeChildren[0]._isTransitioning) {
+ return;
+ }
+ const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6);
+ if (startEvent.defaultPrevented) {
+ return;
+ }
+ for (const activeInstance of activeChildren) {
+ activeInstance.hide();
+ }
+ const dimension = this._getDimension();
+ this._element.classList.remove(CLASS_NAME_COLLAPSE);
+ this._element.classList.add(CLASS_NAME_COLLAPSING);
+ this._element.style[dimension] = 0;
+ this._addAriaAndCollapsedClass(this._triggerArray, true);
+ this._isTransitioning = true;
+ const complete = () => {
+ this._isTransitioning = false;
+ this._element.classList.remove(CLASS_NAME_COLLAPSING);
+ this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);
+ this._element.style[dimension] = '';
+ EventHandler.trigger(this._element, EVENT_SHOWN$6);
+ };
+ const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
+ const scrollSize = `scroll${capitalizedDimension}`;
+ this._queueCallback(complete, this._element, true);
+ this._element.style[dimension] = `${this._element[scrollSize]}px`;
+ }
+ hide() {
+ if (this._isTransitioning || !this._isShown()) {
+ return;
+ }
+ const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6);
+ if (startEvent.defaultPrevented) {
+ return;
+ }
+ const dimension = this._getDimension();
+ this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;
+ reflow(this._element);
+ this._element.classList.add(CLASS_NAME_COLLAPSING);
+ this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);
+ for (const trigger of this._triggerArray) {
+ const element = SelectorEngine.getElementFromSelector(trigger);
+ if (element && !this._isShown(element)) {
+ this._addAriaAndCollapsedClass([trigger], false);
+ }
+ }
+ this._isTransitioning = true;
+ const complete = () => {
+ this._isTransitioning = false;
+ this._element.classList.remove(CLASS_NAME_COLLAPSING);
+ this._element.classList.add(CLASS_NAME_COLLAPSE);
+ EventHandler.trigger(this._element, EVENT_HIDDEN$6);
+ };
+ this._element.style[dimension] = '';
+ this._queueCallback(complete, this._element, true);
+ }
+ _isShown(element = this._element) {
+ return element.classList.contains(CLASS_NAME_SHOW$7);
+ }
+
+ // Private
+ _configAfterMerge(config) {
+ config.toggle = Boolean(config.toggle); // Coerce string values
+ config.parent = getElement(config.parent);
+ return config;
+ }
+ _getDimension() {
+ return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;
+ }
+ _initializeChildren() {
+ if (!this._config.parent) {
+ return;
+ }
+ const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4);
+ for (const element of children) {
+ const selected = SelectorEngine.getElementFromSelector(element);
+ if (selected) {
+ this._addAriaAndCollapsedClass([element], this._isShown(selected));
+ }
+ }
+ }
+ _getFirstLevelChildren(selector) {
+ const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);
+ // remove children if greater depth
+ return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element));
+ }
+ _addAriaAndCollapsedClass(triggerArray, isOpen) {
+ if (!triggerArray.length) {
+ return;
+ }
+ for (const element of triggerArray) {
+ element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);
+ element.setAttribute('aria-expanded', isOpen);
+ }
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ const _config = {};
+ if (typeof config === 'string' && /show|hide/.test(config)) {
+ _config.toggle = false;
+ }
+ return this.each(function () {
+ const data = Collapse.getOrCreateInstance(this, _config);
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config]();
+ }
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) {
+ // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
+ if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') {
+ event.preventDefault();
+ }
+ for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {
+ Collapse.getOrCreateInstance(element, {
+ toggle: false
+ }).toggle();
+ }
+ });
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Collapse);
+
+ var top = 'top';
+ var bottom = 'bottom';
+ var right = 'right';
+ var left = 'left';
+ var auto = 'auto';
+ var basePlacements = [top, bottom, right, left];
+ var start = 'start';
+ var end = 'end';
+ var clippingParents = 'clippingParents';
+ var viewport = 'viewport';
+ var popper = 'popper';
+ var reference = 'reference';
+ var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {
+ return acc.concat([placement + "-" + start, placement + "-" + end]);
+ }, []);
+ var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {
+ return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
+ }, []); // modifiers that need to read the DOM
+
+ var beforeRead = 'beforeRead';
+ var read = 'read';
+ var afterRead = 'afterRead'; // pure-logic modifiers
+
+ var beforeMain = 'beforeMain';
+ var main = 'main';
+ var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)
+
+ var beforeWrite = 'beforeWrite';
+ var write = 'write';
+ var afterWrite = 'afterWrite';
+ var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];
+
+ function getNodeName(element) {
+ return element ? (element.nodeName || '').toLowerCase() : null;
+ }
+
+ function getWindow(node) {
+ if (node == null) {
+ return window;
+ }
+
+ if (node.toString() !== '[object Window]') {
+ var ownerDocument = node.ownerDocument;
+ return ownerDocument ? ownerDocument.defaultView || window : window;
+ }
+
+ return node;
+ }
+
+ function isElement(node) {
+ var OwnElement = getWindow(node).Element;
+ return node instanceof OwnElement || node instanceof Element;
+ }
+
+ function isHTMLElement(node) {
+ var OwnElement = getWindow(node).HTMLElement;
+ return node instanceof OwnElement || node instanceof HTMLElement;
+ }
+
+ function isShadowRoot(node) {
+ // IE 11 has no ShadowRoot
+ if (typeof ShadowRoot === 'undefined') {
+ return false;
+ }
+
+ var OwnElement = getWindow(node).ShadowRoot;
+ return node instanceof OwnElement || node instanceof ShadowRoot;
+ }
+
+ // and applies them to the HTMLElements such as popper and arrow
+
+ function applyStyles(_ref) {
+ var state = _ref.state;
+ Object.keys(state.elements).forEach(function (name) {
+ var style = state.styles[name] || {};
+ var attributes = state.attributes[name] || {};
+ var element = state.elements[name]; // arrow is optional + virtual elements
+
+ if (!isHTMLElement(element) || !getNodeName(element)) {
+ return;
+ } // Flow doesn't support to extend this property, but it's the most
+ // effective way to apply styles to an HTMLElement
+ // $FlowFixMe[cannot-write]
+
+
+ Object.assign(element.style, style);
+ Object.keys(attributes).forEach(function (name) {
+ var value = attributes[name];
+
+ if (value === false) {
+ element.removeAttribute(name);
+ } else {
+ element.setAttribute(name, value === true ? '' : value);
+ }
+ });
+ });
+ }
+
+ function effect$2(_ref2) {
+ var state = _ref2.state;
+ var initialStyles = {
+ popper: {
+ position: state.options.strategy,
+ left: '0',
+ top: '0',
+ margin: '0'
+ },
+ arrow: {
+ position: 'absolute'
+ },
+ reference: {}
+ };
+ Object.assign(state.elements.popper.style, initialStyles.popper);
+ state.styles = initialStyles;
+
+ if (state.elements.arrow) {
+ Object.assign(state.elements.arrow.style, initialStyles.arrow);
+ }
+
+ return function () {
+ Object.keys(state.elements).forEach(function (name) {
+ var element = state.elements[name];
+ var attributes = state.attributes[name] || {};
+ var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them
+
+ var style = styleProperties.reduce(function (style, property) {
+ style[property] = '';
+ return style;
+ }, {}); // arrow is optional + virtual elements
+
+ if (!isHTMLElement(element) || !getNodeName(element)) {
+ return;
+ }
+
+ Object.assign(element.style, style);
+ Object.keys(attributes).forEach(function (attribute) {
+ element.removeAttribute(attribute);
+ });
+ });
+ };
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const applyStyles$1 = {
+ name: 'applyStyles',
+ enabled: true,
+ phase: 'write',
+ fn: applyStyles,
+ effect: effect$2,
+ requires: ['computeStyles']
+ };
+
+ function getBasePlacement(placement) {
+ return placement.split('-')[0];
+ }
+
+ var max = Math.max;
+ var min = Math.min;
+ var round = Math.round;
+
+ function getUAString() {
+ var uaData = navigator.userAgentData;
+
+ if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {
+ return uaData.brands.map(function (item) {
+ return item.brand + "/" + item.version;
+ }).join(' ');
+ }
+
+ return navigator.userAgent;
+ }
+
+ function isLayoutViewport() {
+ return !/^((?!chrome|android).)*safari/i.test(getUAString());
+ }
+
+ function getBoundingClientRect(element, includeScale, isFixedStrategy) {
+ if (includeScale === void 0) {
+ includeScale = false;
+ }
+
+ if (isFixedStrategy === void 0) {
+ isFixedStrategy = false;
+ }
+
+ var clientRect = element.getBoundingClientRect();
+ var scaleX = 1;
+ var scaleY = 1;
+
+ if (includeScale && isHTMLElement(element)) {
+ scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;
+ scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;
+ }
+
+ var _ref = isElement(element) ? getWindow(element) : window,
+ visualViewport = _ref.visualViewport;
+
+ var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;
+ var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;
+ var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;
+ var width = clientRect.width / scaleX;
+ var height = clientRect.height / scaleY;
+ return {
+ width: width,
+ height: height,
+ top: y,
+ right: x + width,
+ bottom: y + height,
+ left: x,
+ x: x,
+ y: y
+ };
+ }
+
+ // means it doesn't take into account transforms.
+
+ function getLayoutRect(element) {
+ var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.
+ // Fixes https://github.com/popperjs/popper-core/issues/1223
+
+ var width = element.offsetWidth;
+ var height = element.offsetHeight;
+
+ if (Math.abs(clientRect.width - width) <= 1) {
+ width = clientRect.width;
+ }
+
+ if (Math.abs(clientRect.height - height) <= 1) {
+ height = clientRect.height;
+ }
+
+ return {
+ x: element.offsetLeft,
+ y: element.offsetTop,
+ width: width,
+ height: height
+ };
+ }
+
+ function contains(parent, child) {
+ var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method
+
+ if (parent.contains(child)) {
+ return true;
+ } // then fallback to custom implementation with Shadow DOM support
+ else if (rootNode && isShadowRoot(rootNode)) {
+ var next = child;
+
+ do {
+ if (next && parent.isSameNode(next)) {
+ return true;
+ } // $FlowFixMe[prop-missing]: need a better way to handle this...
+
+
+ next = next.parentNode || next.host;
+ } while (next);
+ } // Give up, the result is false
+
+
+ return false;
+ }
+
+ function getComputedStyle$1(element) {
+ return getWindow(element).getComputedStyle(element);
+ }
+
+ function isTableElement(element) {
+ return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
+ }
+
+ function getDocumentElement(element) {
+ // $FlowFixMe[incompatible-return]: assume body is always available
+ return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
+ element.document) || window.document).documentElement;
+ }
+
+ function getParentNode(element) {
+ if (getNodeName(element) === 'html') {
+ return element;
+ }
+
+ return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
+ // $FlowFixMe[incompatible-return]
+ // $FlowFixMe[prop-missing]
+ element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
+ element.parentNode || ( // DOM Element detected
+ isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
+ // $FlowFixMe[incompatible-call]: HTMLElement is a Node
+ getDocumentElement(element) // fallback
+
+ );
+ }
+
+ function getTrueOffsetParent(element) {
+ if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
+ getComputedStyle$1(element).position === 'fixed') {
+ return null;
+ }
+
+ return element.offsetParent;
+ } // `.offsetParent` reports `null` for fixed elements, while absolute elements
+ // return the containing block
+
+
+ function getContainingBlock(element) {
+ var isFirefox = /firefox/i.test(getUAString());
+ var isIE = /Trident/i.test(getUAString());
+
+ if (isIE && isHTMLElement(element)) {
+ // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport
+ var elementCss = getComputedStyle$1(element);
+
+ if (elementCss.position === 'fixed') {
+ return null;
+ }
+ }
+
+ var currentNode = getParentNode(element);
+
+ if (isShadowRoot(currentNode)) {
+ currentNode = currentNode.host;
+ }
+
+ while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
+ var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that
+ // create a containing block.
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
+
+ if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {
+ return currentNode;
+ } else {
+ currentNode = currentNode.parentNode;
+ }
+ }
+
+ return null;
+ } // Gets the closest ancestor positioned element. Handles some edge cases,
+ // such as table ancestors and cross browser bugs.
+
+
+ function getOffsetParent(element) {
+ var window = getWindow(element);
+ var offsetParent = getTrueOffsetParent(element);
+
+ while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') {
+ offsetParent = getTrueOffsetParent(offsetParent);
+ }
+
+ if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) {
+ return window;
+ }
+
+ return offsetParent || getContainingBlock(element) || window;
+ }
+
+ function getMainAxisFromPlacement(placement) {
+ return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';
+ }
+
+ function within(min$1, value, max$1) {
+ return max(min$1, min(value, max$1));
+ }
+ function withinMaxClamp(min, value, max) {
+ var v = within(min, value, max);
+ return v > max ? max : v;
+ }
+
+ function getFreshSideObject() {
+ return {
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ };
+ }
+
+ function mergePaddingObject(paddingObject) {
+ return Object.assign({}, getFreshSideObject(), paddingObject);
+ }
+
+ function expandToHashMap(value, keys) {
+ return keys.reduce(function (hashMap, key) {
+ hashMap[key] = value;
+ return hashMap;
+ }, {});
+ }
+
+ var toPaddingObject = function toPaddingObject(padding, state) {
+ padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {
+ placement: state.placement
+ })) : padding;
+ return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
+ };
+
+ function arrow(_ref) {
+ var _state$modifiersData$;
+
+ var state = _ref.state,
+ name = _ref.name,
+ options = _ref.options;
+ var arrowElement = state.elements.arrow;
+ var popperOffsets = state.modifiersData.popperOffsets;
+ var basePlacement = getBasePlacement(state.placement);
+ var axis = getMainAxisFromPlacement(basePlacement);
+ var isVertical = [left, right].indexOf(basePlacement) >= 0;
+ var len = isVertical ? 'height' : 'width';
+
+ if (!arrowElement || !popperOffsets) {
+ return;
+ }
+
+ var paddingObject = toPaddingObject(options.padding, state);
+ var arrowRect = getLayoutRect(arrowElement);
+ var minProp = axis === 'y' ? top : left;
+ var maxProp = axis === 'y' ? bottom : right;
+ var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];
+ var startDiff = popperOffsets[axis] - state.rects.reference[axis];
+ var arrowOffsetParent = getOffsetParent(arrowElement);
+ var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
+ var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is
+ // outside of the popper bounds
+
+ var min = paddingObject[minProp];
+ var max = clientSize - arrowRect[len] - paddingObject[maxProp];
+ var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;
+ var offset = within(min, center, max); // Prevents breaking syntax highlighting...
+
+ var axisProp = axis;
+ state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);
+ }
+
+ function effect$1(_ref2) {
+ var state = _ref2.state,
+ options = _ref2.options;
+ var _options$element = options.element,
+ arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;
+
+ if (arrowElement == null) {
+ return;
+ } // CSS selector
+
+
+ if (typeof arrowElement === 'string') {
+ arrowElement = state.elements.popper.querySelector(arrowElement);
+
+ if (!arrowElement) {
+ return;
+ }
+ }
+
+ if (!contains(state.elements.popper, arrowElement)) {
+ return;
+ }
+
+ state.elements.arrow = arrowElement;
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const arrow$1 = {
+ name: 'arrow',
+ enabled: true,
+ phase: 'main',
+ fn: arrow,
+ effect: effect$1,
+ requires: ['popperOffsets'],
+ requiresIfExists: ['preventOverflow']
+ };
+
+ function getVariation(placement) {
+ return placement.split('-')[1];
+ }
+
+ var unsetSides = {
+ top: 'auto',
+ right: 'auto',
+ bottom: 'auto',
+ left: 'auto'
+ }; // Round the offsets to the nearest suitable subpixel based on the DPR.
+ // Zooming can change the DPR, but it seems to report a value that will
+ // cleanly divide the values into the appropriate subpixels.
+
+ function roundOffsetsByDPR(_ref, win) {
+ var x = _ref.x,
+ y = _ref.y;
+ var dpr = win.devicePixelRatio || 1;
+ return {
+ x: round(x * dpr) / dpr || 0,
+ y: round(y * dpr) / dpr || 0
+ };
+ }
+
+ function mapToStyles(_ref2) {
+ var _Object$assign2;
+
+ var popper = _ref2.popper,
+ popperRect = _ref2.popperRect,
+ placement = _ref2.placement,
+ variation = _ref2.variation,
+ offsets = _ref2.offsets,
+ position = _ref2.position,
+ gpuAcceleration = _ref2.gpuAcceleration,
+ adaptive = _ref2.adaptive,
+ roundOffsets = _ref2.roundOffsets,
+ isFixed = _ref2.isFixed;
+ var _offsets$x = offsets.x,
+ x = _offsets$x === void 0 ? 0 : _offsets$x,
+ _offsets$y = offsets.y,
+ y = _offsets$y === void 0 ? 0 : _offsets$y;
+
+ var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({
+ x: x,
+ y: y
+ }) : {
+ x: x,
+ y: y
+ };
+
+ x = _ref3.x;
+ y = _ref3.y;
+ var hasX = offsets.hasOwnProperty('x');
+ var hasY = offsets.hasOwnProperty('y');
+ var sideX = left;
+ var sideY = top;
+ var win = window;
+
+ if (adaptive) {
+ var offsetParent = getOffsetParent(popper);
+ var heightProp = 'clientHeight';
+ var widthProp = 'clientWidth';
+
+ if (offsetParent === getWindow(popper)) {
+ offsetParent = getDocumentElement(popper);
+
+ if (getComputedStyle$1(offsetParent).position !== 'static' && position === 'absolute') {
+ heightProp = 'scrollHeight';
+ widthProp = 'scrollWidth';
+ }
+ } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
+
+
+ offsetParent = offsetParent;
+
+ if (placement === top || (placement === left || placement === right) && variation === end) {
+ sideY = bottom;
+ var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]
+ offsetParent[heightProp];
+ y -= offsetY - popperRect.height;
+ y *= gpuAcceleration ? 1 : -1;
+ }
+
+ if (placement === left || (placement === top || placement === bottom) && variation === end) {
+ sideX = right;
+ var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]
+ offsetParent[widthProp];
+ x -= offsetX - popperRect.width;
+ x *= gpuAcceleration ? 1 : -1;
+ }
+ }
+
+ var commonStyles = Object.assign({
+ position: position
+ }, adaptive && unsetSides);
+
+ var _ref4 = roundOffsets === true ? roundOffsetsByDPR({
+ x: x,
+ y: y
+ }, getWindow(popper)) : {
+ x: x,
+ y: y
+ };
+
+ x = _ref4.x;
+ y = _ref4.y;
+
+ if (gpuAcceleration) {
+ var _Object$assign;
+
+ return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
+ }
+
+ return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
+ }
+
+ function computeStyles(_ref5) {
+ var state = _ref5.state,
+ options = _ref5.options;
+ var _options$gpuAccelerat = options.gpuAcceleration,
+ gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,
+ _options$adaptive = options.adaptive,
+ adaptive = _options$adaptive === void 0 ? true : _options$adaptive,
+ _options$roundOffsets = options.roundOffsets,
+ roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
+ var commonStyles = {
+ placement: getBasePlacement(state.placement),
+ variation: getVariation(state.placement),
+ popper: state.elements.popper,
+ popperRect: state.rects.popper,
+ gpuAcceleration: gpuAcceleration,
+ isFixed: state.options.strategy === 'fixed'
+ };
+
+ if (state.modifiersData.popperOffsets != null) {
+ state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
+ offsets: state.modifiersData.popperOffsets,
+ position: state.options.strategy,
+ adaptive: adaptive,
+ roundOffsets: roundOffsets
+ })));
+ }
+
+ if (state.modifiersData.arrow != null) {
+ state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
+ offsets: state.modifiersData.arrow,
+ position: 'absolute',
+ adaptive: false,
+ roundOffsets: roundOffsets
+ })));
+ }
+
+ state.attributes.popper = Object.assign({}, state.attributes.popper, {
+ 'data-popper-placement': state.placement
+ });
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const computeStyles$1 = {
+ name: 'computeStyles',
+ enabled: true,
+ phase: 'beforeWrite',
+ fn: computeStyles,
+ data: {}
+ };
+
+ var passive = {
+ passive: true
+ };
+
+ function effect(_ref) {
+ var state = _ref.state,
+ instance = _ref.instance,
+ options = _ref.options;
+ var _options$scroll = options.scroll,
+ scroll = _options$scroll === void 0 ? true : _options$scroll,
+ _options$resize = options.resize,
+ resize = _options$resize === void 0 ? true : _options$resize;
+ var window = getWindow(state.elements.popper);
+ var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
+
+ if (scroll) {
+ scrollParents.forEach(function (scrollParent) {
+ scrollParent.addEventListener('scroll', instance.update, passive);
+ });
+ }
+
+ if (resize) {
+ window.addEventListener('resize', instance.update, passive);
+ }
+
+ return function () {
+ if (scroll) {
+ scrollParents.forEach(function (scrollParent) {
+ scrollParent.removeEventListener('scroll', instance.update, passive);
+ });
+ }
+
+ if (resize) {
+ window.removeEventListener('resize', instance.update, passive);
+ }
+ };
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const eventListeners = {
+ name: 'eventListeners',
+ enabled: true,
+ phase: 'write',
+ fn: function fn() {},
+ effect: effect,
+ data: {}
+ };
+
+ var hash$1 = {
+ left: 'right',
+ right: 'left',
+ bottom: 'top',
+ top: 'bottom'
+ };
+ function getOppositePlacement(placement) {
+ return placement.replace(/left|right|bottom|top/g, function (matched) {
+ return hash$1[matched];
+ });
+ }
+
+ var hash = {
+ start: 'end',
+ end: 'start'
+ };
+ function getOppositeVariationPlacement(placement) {
+ return placement.replace(/start|end/g, function (matched) {
+ return hash[matched];
+ });
+ }
+
+ function getWindowScroll(node) {
+ var win = getWindow(node);
+ var scrollLeft = win.pageXOffset;
+ var scrollTop = win.pageYOffset;
+ return {
+ scrollLeft: scrollLeft,
+ scrollTop: scrollTop
+ };
+ }
+
+ function getWindowScrollBarX(element) {
+ // If <html> has a CSS width greater than the viewport, then this will be
+ // incorrect for RTL.
+ // Popper 1 is broken in this case and never had a bug report so let's assume
+ // it's not an issue. I don't think anyone ever specifies width on <html>
+ // anyway.
+ // Browsers where the left scrollbar doesn't cause an issue report `0` for
+ // this (e.g. Edge 2019, IE11, Safari)
+ return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
+ }
+
+ function getViewportRect(element, strategy) {
+ var win = getWindow(element);
+ var html = getDocumentElement(element);
+ var visualViewport = win.visualViewport;
+ var width = html.clientWidth;
+ var height = html.clientHeight;
+ var x = 0;
+ var y = 0;
+
+ if (visualViewport) {
+ width = visualViewport.width;
+ height = visualViewport.height;
+ var layoutViewport = isLayoutViewport();
+
+ if (layoutViewport || !layoutViewport && strategy === 'fixed') {
+ x = visualViewport.offsetLeft;
+ y = visualViewport.offsetTop;
+ }
+ }
+
+ return {
+ width: width,
+ height: height,
+ x: x + getWindowScrollBarX(element),
+ y: y
+ };
+ }
+
+ // of the `<html>` and `<body>` rect bounds if horizontally scrollable
+
+ function getDocumentRect(element) {
+ var _element$ownerDocumen;
+
+ var html = getDocumentElement(element);
+ var winScroll = getWindowScroll(element);
+ var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
+ var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
+ var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
+ var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
+ var y = -winScroll.scrollTop;
+
+ if (getComputedStyle$1(body || html).direction === 'rtl') {
+ x += max(html.clientWidth, body ? body.clientWidth : 0) - width;
+ }
+
+ return {
+ width: width,
+ height: height,
+ x: x,
+ y: y
+ };
+ }
+
+ function isScrollParent(element) {
+ // Firefox wants us to check `-x` and `-y` variations as well
+ var _getComputedStyle = getComputedStyle$1(element),
+ overflow = _getComputedStyle.overflow,
+ overflowX = _getComputedStyle.overflowX,
+ overflowY = _getComputedStyle.overflowY;
+
+ return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
+ }
+
+ function getScrollParent(node) {
+ if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
+ // $FlowFixMe[incompatible-return]: assume body is always available
+ return node.ownerDocument.body;
+ }
+
+ if (isHTMLElement(node) && isScrollParent(node)) {
+ return node;
+ }
+
+ return getScrollParent(getParentNode(node));
+ }
+
+ /*
+ given a DOM element, return the list of all scroll parents, up the list of ancesors
+ until we get to the top window object. This list is what we attach scroll listeners
+ to, because if any of these parent elements scroll, we'll need to re-calculate the
+ reference element's position.
+ */
+
+ function listScrollParents(element, list) {
+ var _element$ownerDocumen;
+
+ if (list === void 0) {
+ list = [];
+ }
+
+ var scrollParent = getScrollParent(element);
+ var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
+ var win = getWindow(scrollParent);
+ var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
+ var updatedList = list.concat(target);
+ return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
+ updatedList.concat(listScrollParents(getParentNode(target)));
+ }
+
+ function rectToClientRect(rect) {
+ return Object.assign({}, rect, {
+ left: rect.x,
+ top: rect.y,
+ right: rect.x + rect.width,
+ bottom: rect.y + rect.height
+ });
+ }
+
+ function getInnerBoundingClientRect(element, strategy) {
+ var rect = getBoundingClientRect(element, false, strategy === 'fixed');
+ rect.top = rect.top + element.clientTop;
+ rect.left = rect.left + element.clientLeft;
+ rect.bottom = rect.top + element.clientHeight;
+ rect.right = rect.left + element.clientWidth;
+ rect.width = element.clientWidth;
+ rect.height = element.clientHeight;
+ rect.x = rect.left;
+ rect.y = rect.top;
+ return rect;
+ }
+
+ function getClientRectFromMixedType(element, clippingParent, strategy) {
+ return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
+ } // A "clipping parent" is an overflowable container with the characteristic of
+ // clipping (or hiding) overflowing elements with a position different from
+ // `initial`
+
+
+ function getClippingParents(element) {
+ var clippingParents = listScrollParents(getParentNode(element));
+ var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0;
+ var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
+
+ if (!isElement(clipperElement)) {
+ return [];
+ } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414
+
+
+ return clippingParents.filter(function (clippingParent) {
+ return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';
+ });
+ } // Gets the maximum area that the element is visible in due to any number of
+ // clipping parents
+
+
+ function getClippingRect(element, boundary, rootBoundary, strategy) {
+ var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);
+ var clippingParents = [].concat(mainClippingParents, [rootBoundary]);
+ var firstClippingParent = clippingParents[0];
+ var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {
+ var rect = getClientRectFromMixedType(element, clippingParent, strategy);
+ accRect.top = max(rect.top, accRect.top);
+ accRect.right = min(rect.right, accRect.right);
+ accRect.bottom = min(rect.bottom, accRect.bottom);
+ accRect.left = max(rect.left, accRect.left);
+ return accRect;
+ }, getClientRectFromMixedType(element, firstClippingParent, strategy));
+ clippingRect.width = clippingRect.right - clippingRect.left;
+ clippingRect.height = clippingRect.bottom - clippingRect.top;
+ clippingRect.x = clippingRect.left;
+ clippingRect.y = clippingRect.top;
+ return clippingRect;
+ }
+
+ function computeOffsets(_ref) {
+ var reference = _ref.reference,
+ element = _ref.element,
+ placement = _ref.placement;
+ var basePlacement = placement ? getBasePlacement(placement) : null;
+ var variation = placement ? getVariation(placement) : null;
+ var commonX = reference.x + reference.width / 2 - element.width / 2;
+ var commonY = reference.y + reference.height / 2 - element.height / 2;
+ var offsets;
+
+ switch (basePlacement) {
+ case top:
+ offsets = {
+ x: commonX,
+ y: reference.y - element.height
+ };
+ break;
+
+ case bottom:
+ offsets = {
+ x: commonX,
+ y: reference.y + reference.height
+ };
+ break;
+
+ case right:
+ offsets = {
+ x: reference.x + reference.width,
+ y: commonY
+ };
+ break;
+
+ case left:
+ offsets = {
+ x: reference.x - element.width,
+ y: commonY
+ };
+ break;
+
+ default:
+ offsets = {
+ x: reference.x,
+ y: reference.y
+ };
+ }
+
+ var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
+
+ if (mainAxis != null) {
+ var len = mainAxis === 'y' ? 'height' : 'width';
+
+ switch (variation) {
+ case start:
+ offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);
+ break;
+
+ case end:
+ offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);
+ break;
+ }
+ }
+
+ return offsets;
+ }
+
+ function detectOverflow(state, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var _options = options,
+ _options$placement = _options.placement,
+ placement = _options$placement === void 0 ? state.placement : _options$placement,
+ _options$strategy = _options.strategy,
+ strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,
+ _options$boundary = _options.boundary,
+ boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,
+ _options$rootBoundary = _options.rootBoundary,
+ rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,
+ _options$elementConte = _options.elementContext,
+ elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,
+ _options$altBoundary = _options.altBoundary,
+ altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,
+ _options$padding = _options.padding,
+ padding = _options$padding === void 0 ? 0 : _options$padding;
+ var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
+ var altContext = elementContext === popper ? reference : popper;
+ var popperRect = state.rects.popper;
+ var element = state.elements[altBoundary ? altContext : elementContext];
+ var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);
+ var referenceClientRect = getBoundingClientRect(state.elements.reference);
+ var popperOffsets = computeOffsets({
+ reference: referenceClientRect,
+ element: popperRect,
+ strategy: 'absolute',
+ placement: placement
+ });
+ var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));
+ var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect
+ // 0 or negative = within the clipping rect
+
+ var overflowOffsets = {
+ top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
+ bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
+ left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
+ right: elementClientRect.right - clippingClientRect.right + paddingObject.right
+ };
+ var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element
+
+ if (elementContext === popper && offsetData) {
+ var offset = offsetData[placement];
+ Object.keys(overflowOffsets).forEach(function (key) {
+ var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
+ var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
+ overflowOffsets[key] += offset[axis] * multiply;
+ });
+ }
+
+ return overflowOffsets;
+ }
+
+ function computeAutoPlacement(state, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var _options = options,
+ placement = _options.placement,
+ boundary = _options.boundary,
+ rootBoundary = _options.rootBoundary,
+ padding = _options.padding,
+ flipVariations = _options.flipVariations,
+ _options$allowedAutoP = _options.allowedAutoPlacements,
+ allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP;
+ var variation = getVariation(placement);
+ var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {
+ return getVariation(placement) === variation;
+ }) : basePlacements;
+ var allowedPlacements = placements$1.filter(function (placement) {
+ return allowedAutoPlacements.indexOf(placement) >= 0;
+ });
+
+ if (allowedPlacements.length === 0) {
+ allowedPlacements = placements$1;
+ } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...
+
+
+ var overflows = allowedPlacements.reduce(function (acc, placement) {
+ acc[placement] = detectOverflow(state, {
+ placement: placement,
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ padding: padding
+ })[getBasePlacement(placement)];
+ return acc;
+ }, {});
+ return Object.keys(overflows).sort(function (a, b) {
+ return overflows[a] - overflows[b];
+ });
+ }
+
+ function getExpandedFallbackPlacements(placement) {
+ if (getBasePlacement(placement) === auto) {
+ return [];
+ }
+
+ var oppositePlacement = getOppositePlacement(placement);
+ return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
+ }
+
+ function flip(_ref) {
+ var state = _ref.state,
+ options = _ref.options,
+ name = _ref.name;
+
+ if (state.modifiersData[name]._skip) {
+ return;
+ }
+
+ var _options$mainAxis = options.mainAxis,
+ checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+ _options$altAxis = options.altAxis,
+ checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,
+ specifiedFallbackPlacements = options.fallbackPlacements,
+ padding = options.padding,
+ boundary = options.boundary,
+ rootBoundary = options.rootBoundary,
+ altBoundary = options.altBoundary,
+ _options$flipVariatio = options.flipVariations,
+ flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,
+ allowedAutoPlacements = options.allowedAutoPlacements;
+ var preferredPlacement = state.options.placement;
+ var basePlacement = getBasePlacement(preferredPlacement);
+ var isBasePlacement = basePlacement === preferredPlacement;
+ var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));
+ var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {
+ return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {
+ placement: placement,
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ padding: padding,
+ flipVariations: flipVariations,
+ allowedAutoPlacements: allowedAutoPlacements
+ }) : placement);
+ }, []);
+ var referenceRect = state.rects.reference;
+ var popperRect = state.rects.popper;
+ var checksMap = new Map();
+ var makeFallbackChecks = true;
+ var firstFittingPlacement = placements[0];
+
+ for (var i = 0; i < placements.length; i++) {
+ var placement = placements[i];
+
+ var _basePlacement = getBasePlacement(placement);
+
+ var isStartVariation = getVariation(placement) === start;
+ var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;
+ var len = isVertical ? 'width' : 'height';
+ var overflow = detectOverflow(state, {
+ placement: placement,
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ altBoundary: altBoundary,
+ padding: padding
+ });
+ var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;
+
+ if (referenceRect[len] > popperRect[len]) {
+ mainVariationSide = getOppositePlacement(mainVariationSide);
+ }
+
+ var altVariationSide = getOppositePlacement(mainVariationSide);
+ var checks = [];
+
+ if (checkMainAxis) {
+ checks.push(overflow[_basePlacement] <= 0);
+ }
+
+ if (checkAltAxis) {
+ checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);
+ }
+
+ if (checks.every(function (check) {
+ return check;
+ })) {
+ firstFittingPlacement = placement;
+ makeFallbackChecks = false;
+ break;
+ }
+
+ checksMap.set(placement, checks);
+ }
+
+ if (makeFallbackChecks) {
+ // `2` may be desired in some cases – research later
+ var numberOfChecks = flipVariations ? 3 : 1;
+
+ var _loop = function _loop(_i) {
+ var fittingPlacement = placements.find(function (placement) {
+ var checks = checksMap.get(placement);
+
+ if (checks) {
+ return checks.slice(0, _i).every(function (check) {
+ return check;
+ });
+ }
+ });
+
+ if (fittingPlacement) {
+ firstFittingPlacement = fittingPlacement;
+ return "break";
+ }
+ };
+
+ for (var _i = numberOfChecks; _i > 0; _i--) {
+ var _ret = _loop(_i);
+
+ if (_ret === "break") break;
+ }
+ }
+
+ if (state.placement !== firstFittingPlacement) {
+ state.modifiersData[name]._skip = true;
+ state.placement = firstFittingPlacement;
+ state.reset = true;
+ }
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const flip$1 = {
+ name: 'flip',
+ enabled: true,
+ phase: 'main',
+ fn: flip,
+ requiresIfExists: ['offset'],
+ data: {
+ _skip: false
+ }
+ };
+
+ function getSideOffsets(overflow, rect, preventedOffsets) {
+ if (preventedOffsets === void 0) {
+ preventedOffsets = {
+ x: 0,
+ y: 0
+ };
+ }
+
+ return {
+ top: overflow.top - rect.height - preventedOffsets.y,
+ right: overflow.right - rect.width + preventedOffsets.x,
+ bottom: overflow.bottom - rect.height + preventedOffsets.y,
+ left: overflow.left - rect.width - preventedOffsets.x
+ };
+ }
+
+ function isAnySideFullyClipped(overflow) {
+ return [top, right, bottom, left].some(function (side) {
+ return overflow[side] >= 0;
+ });
+ }
+
+ function hide(_ref) {
+ var state = _ref.state,
+ name = _ref.name;
+ var referenceRect = state.rects.reference;
+ var popperRect = state.rects.popper;
+ var preventedOffsets = state.modifiersData.preventOverflow;
+ var referenceOverflow = detectOverflow(state, {
+ elementContext: 'reference'
+ });
+ var popperAltOverflow = detectOverflow(state, {
+ altBoundary: true
+ });
+ var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
+ var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
+ var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
+ var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
+ state.modifiersData[name] = {
+ referenceClippingOffsets: referenceClippingOffsets,
+ popperEscapeOffsets: popperEscapeOffsets,
+ isReferenceHidden: isReferenceHidden,
+ hasPopperEscaped: hasPopperEscaped
+ };
+ state.attributes.popper = Object.assign({}, state.attributes.popper, {
+ 'data-popper-reference-hidden': isReferenceHidden,
+ 'data-popper-escaped': hasPopperEscaped
+ });
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const hide$1 = {
+ name: 'hide',
+ enabled: true,
+ phase: 'main',
+ requiresIfExists: ['preventOverflow'],
+ fn: hide
+ };
+
+ function distanceAndSkiddingToXY(placement, rects, offset) {
+ var basePlacement = getBasePlacement(placement);
+ var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;
+
+ var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {
+ placement: placement
+ })) : offset,
+ skidding = _ref[0],
+ distance = _ref[1];
+
+ skidding = skidding || 0;
+ distance = (distance || 0) * invertDistance;
+ return [left, right].indexOf(basePlacement) >= 0 ? {
+ x: distance,
+ y: skidding
+ } : {
+ x: skidding,
+ y: distance
+ };
+ }
+
+ function offset(_ref2) {
+ var state = _ref2.state,
+ options = _ref2.options,
+ name = _ref2.name;
+ var _options$offset = options.offset,
+ offset = _options$offset === void 0 ? [0, 0] : _options$offset;
+ var data = placements.reduce(function (acc, placement) {
+ acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);
+ return acc;
+ }, {});
+ var _data$state$placement = data[state.placement],
+ x = _data$state$placement.x,
+ y = _data$state$placement.y;
+
+ if (state.modifiersData.popperOffsets != null) {
+ state.modifiersData.popperOffsets.x += x;
+ state.modifiersData.popperOffsets.y += y;
+ }
+
+ state.modifiersData[name] = data;
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const offset$1 = {
+ name: 'offset',
+ enabled: true,
+ phase: 'main',
+ requires: ['popperOffsets'],
+ fn: offset
+ };
+
+ function popperOffsets(_ref) {
+ var state = _ref.state,
+ name = _ref.name;
+ // Offsets are the actual position the popper needs to have to be
+ // properly positioned near its reference element
+ // This is the most basic placement, and will be adjusted by
+ // the modifiers in the next step
+ state.modifiersData[name] = computeOffsets({
+ reference: state.rects.reference,
+ element: state.rects.popper,
+ strategy: 'absolute',
+ placement: state.placement
+ });
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const popperOffsets$1 = {
+ name: 'popperOffsets',
+ enabled: true,
+ phase: 'read',
+ fn: popperOffsets,
+ data: {}
+ };
+
+ function getAltAxis(axis) {
+ return axis === 'x' ? 'y' : 'x';
+ }
+
+ function preventOverflow(_ref) {
+ var state = _ref.state,
+ options = _ref.options,
+ name = _ref.name;
+ var _options$mainAxis = options.mainAxis,
+ checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+ _options$altAxis = options.altAxis,
+ checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,
+ boundary = options.boundary,
+ rootBoundary = options.rootBoundary,
+ altBoundary = options.altBoundary,
+ padding = options.padding,
+ _options$tether = options.tether,
+ tether = _options$tether === void 0 ? true : _options$tether,
+ _options$tetherOffset = options.tetherOffset,
+ tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
+ var overflow = detectOverflow(state, {
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ padding: padding,
+ altBoundary: altBoundary
+ });
+ var basePlacement = getBasePlacement(state.placement);
+ var variation = getVariation(state.placement);
+ var isBasePlacement = !variation;
+ var mainAxis = getMainAxisFromPlacement(basePlacement);
+ var altAxis = getAltAxis(mainAxis);
+ var popperOffsets = state.modifiersData.popperOffsets;
+ var referenceRect = state.rects.reference;
+ var popperRect = state.rects.popper;
+ var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {
+ placement: state.placement
+ })) : tetherOffset;
+ var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {
+ mainAxis: tetherOffsetValue,
+ altAxis: tetherOffsetValue
+ } : Object.assign({
+ mainAxis: 0,
+ altAxis: 0
+ }, tetherOffsetValue);
+ var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;
+ var data = {
+ x: 0,
+ y: 0
+ };
+
+ if (!popperOffsets) {
+ return;
+ }
+
+ if (checkMainAxis) {
+ var _offsetModifierState$;
+
+ var mainSide = mainAxis === 'y' ? top : left;
+ var altSide = mainAxis === 'y' ? bottom : right;
+ var len = mainAxis === 'y' ? 'height' : 'width';
+ var offset = popperOffsets[mainAxis];
+ var min$1 = offset + overflow[mainSide];
+ var max$1 = offset - overflow[altSide];
+ var additive = tether ? -popperRect[len] / 2 : 0;
+ var minLen = variation === start ? referenceRect[len] : popperRect[len];
+ var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
+ // outside the reference bounds
+
+ var arrowElement = state.elements.arrow;
+ var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
+ width: 0,
+ height: 0
+ };
+ var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
+ var arrowPaddingMin = arrowPaddingObject[mainSide];
+ var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
+ // to include its full size in the calculation. If the reference is small
+ // and near the edge of a boundary, the popper can overflow even if the
+ // reference is not overflowing as well (e.g. virtual elements with no
+ // width or height)
+
+ var arrowLen = within(0, referenceRect[len], arrowRect[len]);
+ var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;
+ var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;
+ var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
+ var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
+ var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;
+ var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;
+ var tetherMax = offset + maxOffset - offsetModifierValue;
+ var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1);
+ popperOffsets[mainAxis] = preventedOffset;
+ data[mainAxis] = preventedOffset - offset;
+ }
+
+ if (checkAltAxis) {
+ var _offsetModifierState$2;
+
+ var _mainSide = mainAxis === 'x' ? top : left;
+
+ var _altSide = mainAxis === 'x' ? bottom : right;
+
+ var _offset = popperOffsets[altAxis];
+
+ var _len = altAxis === 'y' ? 'height' : 'width';
+
+ var _min = _offset + overflow[_mainSide];
+
+ var _max = _offset - overflow[_altSide];
+
+ var isOriginSide = [top, left].indexOf(basePlacement) !== -1;
+
+ var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;
+
+ var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;
+
+ var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;
+
+ var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);
+
+ popperOffsets[altAxis] = _preventedOffset;
+ data[altAxis] = _preventedOffset - _offset;
+ }
+
+ state.modifiersData[name] = data;
+ } // eslint-disable-next-line import/no-unused-modules
+
+
+ const preventOverflow$1 = {
+ name: 'preventOverflow',
+ enabled: true,
+ phase: 'main',
+ fn: preventOverflow,
+ requiresIfExists: ['offset']
+ };
+
+ function getHTMLElementScroll(element) {
+ return {
+ scrollLeft: element.scrollLeft,
+ scrollTop: element.scrollTop
+ };
+ }
+
+ function getNodeScroll(node) {
+ if (node === getWindow(node) || !isHTMLElement(node)) {
+ return getWindowScroll(node);
+ } else {
+ return getHTMLElementScroll(node);
+ }
+ }
+
+ function isElementScaled(element) {
+ var rect = element.getBoundingClientRect();
+ var scaleX = round(rect.width) / element.offsetWidth || 1;
+ var scaleY = round(rect.height) / element.offsetHeight || 1;
+ return scaleX !== 1 || scaleY !== 1;
+ } // Returns the composite rect of an element relative to its offsetParent.
+ // Composite means it takes into account transforms as well as layout.
+
+
+ function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
+ if (isFixed === void 0) {
+ isFixed = false;
+ }
+
+ var isOffsetParentAnElement = isHTMLElement(offsetParent);
+ var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);
+ var documentElement = getDocumentElement(offsetParent);
+ var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);
+ var scroll = {
+ scrollLeft: 0,
+ scrollTop: 0
+ };
+ var offsets = {
+ x: 0,
+ y: 0
+ };
+
+ if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
+ if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
+ isScrollParent(documentElement)) {
+ scroll = getNodeScroll(offsetParent);
+ }
+
+ if (isHTMLElement(offsetParent)) {
+ offsets = getBoundingClientRect(offsetParent, true);
+ offsets.x += offsetParent.clientLeft;
+ offsets.y += offsetParent.clientTop;
+ } else if (documentElement) {
+ offsets.x = getWindowScrollBarX(documentElement);
+ }
+ }
+
+ return {
+ x: rect.left + scroll.scrollLeft - offsets.x,
+ y: rect.top + scroll.scrollTop - offsets.y,
+ width: rect.width,
+ height: rect.height
+ };
+ }
+
+ function order(modifiers) {
+ var map = new Map();
+ var visited = new Set();
+ var result = [];
+ modifiers.forEach(function (modifier) {
+ map.set(modifier.name, modifier);
+ }); // On visiting object, check for its dependencies and visit them recursively
+
+ function sort(modifier) {
+ visited.add(modifier.name);
+ var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
+ requires.forEach(function (dep) {
+ if (!visited.has(dep)) {
+ var depModifier = map.get(dep);
+
+ if (depModifier) {
+ sort(depModifier);
+ }
+ }
+ });
+ result.push(modifier);
+ }
+
+ modifiers.forEach(function (modifier) {
+ if (!visited.has(modifier.name)) {
+ // check for visited object
+ sort(modifier);
+ }
+ });
+ return result;
+ }
+
+ function orderModifiers(modifiers) {
+ // order based on dependencies
+ var orderedModifiers = order(modifiers); // order based on phase
+
+ return modifierPhases.reduce(function (acc, phase) {
+ return acc.concat(orderedModifiers.filter(function (modifier) {
+ return modifier.phase === phase;
+ }));
+ }, []);
+ }
+
+ function debounce(fn) {
+ var pending;
+ return function () {
+ if (!pending) {
+ pending = new Promise(function (resolve) {
+ Promise.resolve().then(function () {
+ pending = undefined;
+ resolve(fn());
+ });
+ });
+ }
+
+ return pending;
+ };
+ }
+
+ function mergeByName(modifiers) {
+ var merged = modifiers.reduce(function (merged, current) {
+ var existing = merged[current.name];
+ merged[current.name] = existing ? Object.assign({}, existing, current, {
+ options: Object.assign({}, existing.options, current.options),
+ data: Object.assign({}, existing.data, current.data)
+ }) : current;
+ return merged;
+ }, {}); // IE11 does not support Object.values
+
+ return Object.keys(merged).map(function (key) {
+ return merged[key];
+ });
+ }
+
+ var DEFAULT_OPTIONS = {
+ placement: 'bottom',
+ modifiers: [],
+ strategy: 'absolute'
+ };
+
+ function areValidElements() {
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ return !args.some(function (element) {
+ return !(element && typeof element.getBoundingClientRect === 'function');
+ });
+ }
+
+ function popperGenerator(generatorOptions) {
+ if (generatorOptions === void 0) {
+ generatorOptions = {};
+ }
+
+ var _generatorOptions = generatorOptions,
+ _generatorOptions$def = _generatorOptions.defaultModifiers,
+ defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,
+ _generatorOptions$def2 = _generatorOptions.defaultOptions,
+ defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
+ return function createPopper(reference, popper, options) {
+ if (options === void 0) {
+ options = defaultOptions;
+ }
+
+ var state = {
+ placement: 'bottom',
+ orderedModifiers: [],
+ options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),
+ modifiersData: {},
+ elements: {
+ reference: reference,
+ popper: popper
+ },
+ attributes: {},
+ styles: {}
+ };
+ var effectCleanupFns = [];
+ var isDestroyed = false;
+ var instance = {
+ state: state,
+ setOptions: function setOptions(setOptionsAction) {
+ var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;
+ cleanupModifierEffects();
+ state.options = Object.assign({}, defaultOptions, state.options, options);
+ state.scrollParents = {
+ reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],
+ popper: listScrollParents(popper)
+ }; // Orders the modifiers based on their dependencies and `phase`
+ // properties
+
+ var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers
+
+ state.orderedModifiers = orderedModifiers.filter(function (m) {
+ return m.enabled;
+ });
+ runModifierEffects();
+ return instance.update();
+ },
+ // Sync update – it will always be executed, even if not necessary. This
+ // is useful for low frequency updates where sync behavior simplifies the
+ // logic.
+ // For high frequency updates (e.g. `resize` and `scroll` events), always
+ // prefer the async Popper#update method
+ forceUpdate: function forceUpdate() {
+ if (isDestroyed) {
+ return;
+ }
+
+ var _state$elements = state.elements,
+ reference = _state$elements.reference,
+ popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements
+ // anymore
+
+ if (!areValidElements(reference, popper)) {
+ return;
+ } // Store the reference and popper rects to be read by modifiers
+
+
+ state.rects = {
+ reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),
+ popper: getLayoutRect(popper)
+ }; // Modifiers have the ability to reset the current update cycle. The
+ // most common use case for this is the `flip` modifier changing the
+ // placement, which then needs to re-run all the modifiers, because the
+ // logic was previously ran for the previous placement and is therefore
+ // stale/incorrect
+
+ state.reset = false;
+ state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier
+ // is filled with the initial data specified by the modifier. This means
+ // it doesn't persist and is fresh on each update.
+ // To ensure persistent data, use `${name}#persistent`
+
+ state.orderedModifiers.forEach(function (modifier) {
+ return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
+ });
+
+ for (var index = 0; index < state.orderedModifiers.length; index++) {
+ if (state.reset === true) {
+ state.reset = false;
+ index = -1;
+ continue;
+ }
+
+ var _state$orderedModifie = state.orderedModifiers[index],
+ fn = _state$orderedModifie.fn,
+ _state$orderedModifie2 = _state$orderedModifie.options,
+ _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,
+ name = _state$orderedModifie.name;
+
+ if (typeof fn === 'function') {
+ state = fn({
+ state: state,
+ options: _options,
+ name: name,
+ instance: instance
+ }) || state;
+ }
+ }
+ },
+ // Async and optimistically optimized update – it will not be executed if
+ // not necessary (debounced to run at most once-per-tick)
+ update: debounce(function () {
+ return new Promise(function (resolve) {
+ instance.forceUpdate();
+ resolve(state);
+ });
+ }),
+ destroy: function destroy() {
+ cleanupModifierEffects();
+ isDestroyed = true;
+ }
+ };
+
+ if (!areValidElements(reference, popper)) {
+ return instance;
+ }
+
+ instance.setOptions(options).then(function (state) {
+ if (!isDestroyed && options.onFirstUpdate) {
+ options.onFirstUpdate(state);
+ }
+ }); // Modifiers have the ability to execute arbitrary code before the first
+ // update cycle runs. They will be executed in the same order as the update
+ // cycle. This is useful when a modifier adds some persistent data that
+ // other modifiers need to use, but the modifier is run after the dependent
+ // one.
+
+ function runModifierEffects() {
+ state.orderedModifiers.forEach(function (_ref) {
+ var name = _ref.name,
+ _ref$options = _ref.options,
+ options = _ref$options === void 0 ? {} : _ref$options,
+ effect = _ref.effect;
+
+ if (typeof effect === 'function') {
+ var cleanupFn = effect({
+ state: state,
+ name: name,
+ instance: instance,
+ options: options
+ });
+
+ var noopFn = function noopFn() {};
+
+ effectCleanupFns.push(cleanupFn || noopFn);
+ }
+ });
+ }
+
+ function cleanupModifierEffects() {
+ effectCleanupFns.forEach(function (fn) {
+ return fn();
+ });
+ effectCleanupFns = [];
+ }
+
+ return instance;
+ };
+ }
+ var createPopper$2 = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules
+
+ var defaultModifiers$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1];
+ var createPopper$1 = /*#__PURE__*/popperGenerator({
+ defaultModifiers: defaultModifiers$1
+ }); // eslint-disable-next-line import/no-unused-modules
+
+ var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1];
+ var createPopper = /*#__PURE__*/popperGenerator({
+ defaultModifiers: defaultModifiers
+ }); // eslint-disable-next-line import/no-unused-modules
+
+ const Popper = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
+ __proto__: null,
+ afterMain,
+ afterRead,
+ afterWrite,
+ applyStyles: applyStyles$1,
+ arrow: arrow$1,
+ auto,
+ basePlacements,
+ beforeMain,
+ beforeRead,
+ beforeWrite,
+ bottom,
+ clippingParents,
+ computeStyles: computeStyles$1,
+ createPopper,
+ createPopperBase: createPopper$2,
+ createPopperLite: createPopper$1,
+ detectOverflow,
+ end,
+ eventListeners,
+ flip: flip$1,
+ hide: hide$1,
+ left,
+ main,
+ modifierPhases,
+ offset: offset$1,
+ placements,
+ popper,
+ popperGenerator,
+ popperOffsets: popperOffsets$1,
+ preventOverflow: preventOverflow$1,
+ read,
+ reference,
+ right,
+ start,
+ top,
+ variationPlacements,
+ viewport,
+ write
+ }, Symbol.toStringTag, { value: 'Module' }));
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap dropdown.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$a = 'dropdown';
+ const DATA_KEY$6 = 'bs.dropdown';
+ const EVENT_KEY$6 = `.${DATA_KEY$6}`;
+ const DATA_API_KEY$3 = '.data-api';
+ const ESCAPE_KEY$2 = 'Escape';
+ const TAB_KEY$1 = 'Tab';
+ const ARROW_UP_KEY$1 = 'ArrowUp';
+ const ARROW_DOWN_KEY$1 = 'ArrowDown';
+ const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button
+
+ const EVENT_HIDE$5 = `hide${EVENT_KEY$6}`;
+ const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`;
+ const EVENT_SHOW$5 = `show${EVENT_KEY$6}`;
+ const EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`;
+ const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`;
+ const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`;
+ const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`;
+ const CLASS_NAME_SHOW$6 = 'show';
+ const CLASS_NAME_DROPUP = 'dropup';
+ const CLASS_NAME_DROPEND = 'dropend';
+ const CLASS_NAME_DROPSTART = 'dropstart';
+ const CLASS_NAME_DROPUP_CENTER = 'dropup-center';
+ const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center';
+ const SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)';
+ const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`;
+ const SELECTOR_MENU = '.dropdown-menu';
+ const SELECTOR_NAVBAR = '.navbar';
+ const SELECTOR_NAVBAR_NAV = '.navbar-nav';
+ const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';
+ const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';
+ const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';
+ const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';
+ const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';
+ const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';
+ const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';
+ const PLACEMENT_TOPCENTER = 'top';
+ const PLACEMENT_BOTTOMCENTER = 'bottom';
+ const Default$9 = {
+ autoClose: true,
+ boundary: 'clippingParents',
+ display: 'dynamic',
+ offset: [0, 2],
+ popperConfig: null,
+ reference: 'toggle'
+ };
+ const DefaultType$9 = {
+ autoClose: '(boolean|string)',
+ boundary: '(string|element)',
+ display: 'string',
+ offset: '(array|string|function)',
+ popperConfig: '(null|object|function)',
+ reference: '(string|element|object)'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Dropdown extends BaseComponent {
+ constructor(element, config) {
+ super(element, config);
+ this._popper = null;
+ this._parent = this._element.parentNode; // dropdown wrapper
+ // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
+ this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);
+ this._inNavbar = this._detectNavbar();
+ }
+
+ // Getters
+ static get Default() {
+ return Default$9;
+ }
+ static get DefaultType() {
+ return DefaultType$9;
+ }
+ static get NAME() {
+ return NAME$a;
+ }
+
+ // Public
+ toggle() {
+ return this._isShown() ? this.hide() : this.show();
+ }
+ show() {
+ if (isDisabled(this._element) || this._isShown()) {
+ return;
+ }
+ const relatedTarget = {
+ relatedTarget: this._element
+ };
+ const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget);
+ if (showEvent.defaultPrevented) {
+ return;
+ }
+ this._createPopper();
+
+ // If this is a touch-enabled device we add extra
+ // empty mouseover listeners to the body's immediate children;
+ // only needed because of broken event delegation on iOS
+ // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+ if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {
+ for (const element of [].concat(...document.body.children)) {
+ EventHandler.on(element, 'mouseover', noop);
+ }
+ }
+ this._element.focus();
+ this._element.setAttribute('aria-expanded', true);
+ this._menu.classList.add(CLASS_NAME_SHOW$6);
+ this._element.classList.add(CLASS_NAME_SHOW$6);
+ EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget);
+ }
+ hide() {
+ if (isDisabled(this._element) || !this._isShown()) {
+ return;
+ }
+ const relatedTarget = {
+ relatedTarget: this._element
+ };
+ this._completeHide(relatedTarget);
+ }
+ dispose() {
+ if (this._popper) {
+ this._popper.destroy();
+ }
+ super.dispose();
+ }
+ update() {
+ this._inNavbar = this._detectNavbar();
+ if (this._popper) {
+ this._popper.update();
+ }
+ }
+
+ // Private
+ _completeHide(relatedTarget) {
+ const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget);
+ if (hideEvent.defaultPrevented) {
+ return;
+ }
+
+ // If this is a touch-enabled device we remove the extra
+ // empty mouseover listeners we added for iOS support
+ if ('ontouchstart' in document.documentElement) {
+ for (const element of [].concat(...document.body.children)) {
+ EventHandler.off(element, 'mouseover', noop);
+ }
+ }
+ if (this._popper) {
+ this._popper.destroy();
+ }
+ this._menu.classList.remove(CLASS_NAME_SHOW$6);
+ this._element.classList.remove(CLASS_NAME_SHOW$6);
+ this._element.setAttribute('aria-expanded', 'false');
+ Manipulator.removeDataAttribute(this._menu, 'popper');
+ EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);
+ }
+ _getConfig(config) {
+ config = super._getConfig(config);
+ if (typeof config.reference === 'object' && !isElement$1(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {
+ // Popper virtual elements require a getBoundingClientRect method
+ throw new TypeError(`${NAME$a.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);
+ }
+ return config;
+ }
+ _createPopper() {
+ if (typeof Popper === 'undefined') {
+ throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)');
+ }
+ let referenceElement = this._element;
+ if (this._config.reference === 'parent') {
+ referenceElement = this._parent;
+ } else if (isElement$1(this._config.reference)) {
+ referenceElement = getElement(this._config.reference);
+ } else if (typeof this._config.reference === 'object') {
+ referenceElement = this._config.reference;
+ }
+ const popperConfig = this._getPopperConfig();
+ this._popper = createPopper(referenceElement, this._menu, popperConfig);
+ }
+ _isShown() {
+ return this._menu.classList.contains(CLASS_NAME_SHOW$6);
+ }
+ _getPlacement() {
+ const parentDropdown = this._parent;
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
+ return PLACEMENT_RIGHT;
+ }
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
+ return PLACEMENT_LEFT;
+ }
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {
+ return PLACEMENT_TOPCENTER;
+ }
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {
+ return PLACEMENT_BOTTOMCENTER;
+ }
+
+ // We need to trim the value because custom properties can also include spaces
+ const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end';
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
+ return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP;
+ }
+ return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM;
+ }
+ _detectNavbar() {
+ return this._element.closest(SELECTOR_NAVBAR) !== null;
+ }
+ _getOffset() {
+ const {
+ offset
+ } = this._config;
+ if (typeof offset === 'string') {
+ return offset.split(',').map(value => Number.parseInt(value, 10));
+ }
+ if (typeof offset === 'function') {
+ return popperData => offset(popperData, this._element);
+ }
+ return offset;
+ }
+ _getPopperConfig() {
+ const defaultBsPopperConfig = {
+ placement: this._getPlacement(),
+ modifiers: [{
+ name: 'preventOverflow',
+ options: {
+ boundary: this._config.boundary
+ }
+ }, {
+ name: 'offset',
+ options: {
+ offset: this._getOffset()
+ }
+ }]
+ };
+
+ // Disable Popper if we have a static display or Dropdown is in Navbar
+ if (this._inNavbar || this._config.display === 'static') {
+ Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove
+ defaultBsPopperConfig.modifiers = [{
+ name: 'applyStyles',
+ enabled: false
+ }];
+ }
+ return {
+ ...defaultBsPopperConfig,
+ ...execute(this._config.popperConfig, [defaultBsPopperConfig])
+ };
+ }
+ _selectMenuItem({
+ key,
+ target
+ }) {
+ const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element));
+ if (!items.length) {
+ return;
+ }
+
+ // if target isn't included in items (e.g. when expanding the dropdown)
+ // allow cycling to get the last item in case key equals ARROW_UP_KEY
+ getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Dropdown.getOrCreateInstance(this, config);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config]();
+ });
+ }
+ static clearMenus(event) {
+ if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {
+ return;
+ }
+ const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);
+ for (const toggle of openToggles) {
+ const context = Dropdown.getInstance(toggle);
+ if (!context || context._config.autoClose === false) {
+ continue;
+ }
+ const composedPath = event.composedPath();
+ const isMenuTarget = composedPath.includes(context._menu);
+ if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {
+ continue;
+ }
+
+ // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
+ if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) {
+ continue;
+ }
+ const relatedTarget = {
+ relatedTarget: context._element
+ };
+ if (event.type === 'click') {
+ relatedTarget.clickEvent = event;
+ }
+ context._completeHide(relatedTarget);
+ }
+ }
+ static dataApiKeydownHandler(event) {
+ // If not an UP | DOWN | ESCAPE key => not a dropdown command
+ // If input/textarea && if key is other than ESCAPE => not a dropdown command
+
+ const isInput = /input|textarea/i.test(event.target.tagName);
+ const isEscapeEvent = event.key === ESCAPE_KEY$2;
+ const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key);
+ if (!isUpOrDownEvent && !isEscapeEvent) {
+ return;
+ }
+ if (isInput && !isEscapeEvent) {
+ return;
+ }
+ event.preventDefault();
+
+ // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
+ 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);
+ const instance = Dropdown.getOrCreateInstance(getToggleButton);
+ if (isUpOrDownEvent) {
+ event.stopPropagation();
+ instance.show();
+ instance._selectMenuItem(event);
+ return;
+ }
+ if (instance._isShown()) {
+ // else is escape and we check if it is shown
+ event.stopPropagation();
+ instance.hide();
+ getToggleButton.focus();
+ }
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler);
+ EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler);
+ EventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus);
+ EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);
+ EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) {
+ event.preventDefault();
+ Dropdown.getOrCreateInstance(this).toggle();
+ });
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Dropdown);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/backdrop.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$9 = 'backdrop';
+ const CLASS_NAME_FADE$4 = 'fade';
+ const CLASS_NAME_SHOW$5 = 'show';
+ const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`;
+ const Default$8 = {
+ className: 'modal-backdrop',
+ clickCallback: null,
+ isAnimated: false,
+ isVisible: true,
+ // if false, we use the backdrop helper without adding any element to the dom
+ rootElement: 'body' // give the choice to place backdrop under different elements
+ };
+
+ const DefaultType$8 = {
+ className: 'string',
+ clickCallback: '(function|null)',
+ isAnimated: 'boolean',
+ isVisible: 'boolean',
+ rootElement: '(element|string)'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Backdrop extends Config {
+ constructor(config) {
+ super();
+ this._config = this._getConfig(config);
+ this._isAppended = false;
+ this._element = null;
+ }
+
+ // Getters
+ static get Default() {
+ return Default$8;
+ }
+ static get DefaultType() {
+ return DefaultType$8;
+ }
+ static get NAME() {
+ return NAME$9;
+ }
+
+ // Public
+ show(callback) {
+ if (!this._config.isVisible) {
+ execute(callback);
+ return;
+ }
+ this._append();
+ const element = this._getElement();
+ if (this._config.isAnimated) {
+ reflow(element);
+ }
+ element.classList.add(CLASS_NAME_SHOW$5);
+ this._emulateAnimation(() => {
+ execute(callback);
+ });
+ }
+ hide(callback) {
+ if (!this._config.isVisible) {
+ execute(callback);
+ return;
+ }
+ this._getElement().classList.remove(CLASS_NAME_SHOW$5);
+ this._emulateAnimation(() => {
+ this.dispose();
+ execute(callback);
+ });
+ }
+ dispose() {
+ if (!this._isAppended) {
+ return;
+ }
+ EventHandler.off(this._element, EVENT_MOUSEDOWN);
+ this._element.remove();
+ this._isAppended = false;
+ }
+
+ // Private
+ _getElement() {
+ if (!this._element) {
+ const backdrop = document.createElement('div');
+ backdrop.className = this._config.className;
+ if (this._config.isAnimated) {
+ backdrop.classList.add(CLASS_NAME_FADE$4);
+ }
+ this._element = backdrop;
+ }
+ return this._element;
+ }
+ _configAfterMerge(config) {
+ // use getElement() with the default "body" to get a fresh Element on each instantiation
+ config.rootElement = getElement(config.rootElement);
+ return config;
+ }
+ _append() {
+ if (this._isAppended) {
+ return;
+ }
+ const element = this._getElement();
+ this._config.rootElement.append(element);
+ EventHandler.on(element, EVENT_MOUSEDOWN, () => {
+ execute(this._config.clickCallback);
+ });
+ this._isAppended = true;
+ }
+ _emulateAnimation(callback) {
+ executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
+ }
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/focustrap.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$8 = 'focustrap';
+ const DATA_KEY$5 = 'bs.focustrap';
+ const EVENT_KEY$5 = `.${DATA_KEY$5}`;
+ const EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`;
+ const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`;
+ const TAB_KEY = 'Tab';
+ const TAB_NAV_FORWARD = 'forward';
+ const TAB_NAV_BACKWARD = 'backward';
+ const Default$7 = {
+ autofocus: true,
+ trapElement: null // The element to trap focus inside of
+ };
+
+ const DefaultType$7 = {
+ autofocus: 'boolean',
+ trapElement: 'element'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class FocusTrap extends Config {
+ constructor(config) {
+ super();
+ this._config = this._getConfig(config);
+ this._isActive = false;
+ this._lastTabNavDirection = null;
+ }
+
+ // Getters
+ static get Default() {
+ return Default$7;
+ }
+ static get DefaultType() {
+ return DefaultType$7;
+ }
+ static get NAME() {
+ return NAME$8;
+ }
+
+ // Public
+ activate() {
+ if (this._isActive) {
+ return;
+ }
+ if (this._config.autofocus) {
+ this._config.trapElement.focus();
+ }
+ EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop
+ EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event));
+ EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
+ this._isActive = true;
+ }
+ deactivate() {
+ if (!this._isActive) {
+ return;
+ }
+ this._isActive = false;
+ EventHandler.off(document, EVENT_KEY$5);
+ }
+
+ // Private
+ _handleFocusin(event) {
+ const {
+ trapElement
+ } = this._config;
+ if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
+ return;
+ }
+ const elements = SelectorEngine.focusableChildren(trapElement);
+ if (elements.length === 0) {
+ trapElement.focus();
+ } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
+ elements[elements.length - 1].focus();
+ } else {
+ elements[0].focus();
+ }
+ }
+ _handleKeydown(event) {
+ if (event.key !== TAB_KEY) {
+ return;
+ }
+ this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
+ }
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/scrollBar.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
+ const SELECTOR_STICKY_CONTENT = '.sticky-top';
+ const PROPERTY_PADDING = 'padding-right';
+ const PROPERTY_MARGIN = 'margin-right';
+
+ /**
+ * Class definition
+ */
+
+ class ScrollBarHelper {
+ constructor() {
+ this._element = document.body;
+ }
+
+ // Public
+ getWidth() {
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
+ const documentWidth = document.documentElement.clientWidth;
+ return Math.abs(window.innerWidth - documentWidth);
+ }
+ hide() {
+ const width = this.getWidth();
+ this._disableOverFlow();
+ // give padding to element to balance the hidden scrollbar width
+ this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
+ // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
+ this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
+ this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);
+ }
+ reset() {
+ this._resetElementAttributes(this._element, 'overflow');
+ this._resetElementAttributes(this._element, PROPERTY_PADDING);
+ this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);
+ this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);
+ }
+ isOverflowing() {
+ return this.getWidth() > 0;
+ }
+
+ // Private
+ _disableOverFlow() {
+ this._saveInitialAttribute(this._element, 'overflow');
+ this._element.style.overflow = 'hidden';
+ }
+ _setElementAttributes(selector, styleProperty, callback) {
+ const scrollbarWidth = this.getWidth();
+ const manipulationCallBack = element => {
+ if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
+ return;
+ }
+ this._saveInitialAttribute(element, styleProperty);
+ const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);
+ element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);
+ };
+ this._applyManipulationCallback(selector, manipulationCallBack);
+ }
+ _saveInitialAttribute(element, styleProperty) {
+ const actualValue = element.style.getPropertyValue(styleProperty);
+ if (actualValue) {
+ Manipulator.setDataAttribute(element, styleProperty, actualValue);
+ }
+ }
+ _resetElementAttributes(selector, styleProperty) {
+ const manipulationCallBack = element => {
+ const value = Manipulator.getDataAttribute(element, styleProperty);
+ // We only want to remove the property if the value is `null`; the value can also be zero
+ if (value === null) {
+ element.style.removeProperty(styleProperty);
+ return;
+ }
+ Manipulator.removeDataAttribute(element, styleProperty);
+ element.style.setProperty(styleProperty, value);
+ };
+ this._applyManipulationCallback(selector, manipulationCallBack);
+ }
+ _applyManipulationCallback(selector, callBack) {
+ if (isElement$1(selector)) {
+ callBack(selector);
+ return;
+ }
+ for (const sel of SelectorEngine.find(selector, this._element)) {
+ callBack(sel);
+ }
+ }
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap modal.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$7 = 'modal';
+ const DATA_KEY$4 = 'bs.modal';
+ const EVENT_KEY$4 = `.${DATA_KEY$4}`;
+ const DATA_API_KEY$2 = '.data-api';
+ const ESCAPE_KEY$1 = 'Escape';
+ const EVENT_HIDE$4 = `hide${EVENT_KEY$4}`;
+ const EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`;
+ const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`;
+ const EVENT_SHOW$4 = `show${EVENT_KEY$4}`;
+ const EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`;
+ const EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`;
+ const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`;
+ const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`;
+ const EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`;
+ const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`;
+ const CLASS_NAME_OPEN = 'modal-open';
+ const CLASS_NAME_FADE$3 = 'fade';
+ const CLASS_NAME_SHOW$4 = 'show';
+ const CLASS_NAME_STATIC = 'modal-static';
+ const OPEN_SELECTOR$1 = '.modal.show';
+ const SELECTOR_DIALOG = '.modal-dialog';
+ const SELECTOR_MODAL_BODY = '.modal-body';
+ const SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle="modal"]';
+ const Default$6 = {
+ backdrop: true,
+ focus: true,
+ keyboard: true
+ };
+ const DefaultType$6 = {
+ backdrop: '(boolean|string)',
+ focus: 'boolean',
+ keyboard: 'boolean'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Modal extends BaseComponent {
+ constructor(element, config) {
+ super(element, config);
+ this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element);
+ this._backdrop = this._initializeBackDrop();
+ this._focustrap = this._initializeFocusTrap();
+ this._isShown = false;
+ this._isTransitioning = false;
+ this._scrollBar = new ScrollBarHelper();
+ this._addEventListeners();
+ }
+
+ // Getters
+ static get Default() {
+ return Default$6;
+ }
+ static get DefaultType() {
+ return DefaultType$6;
+ }
+ static get NAME() {
+ return NAME$7;
+ }
+
+ // Public
+ toggle(relatedTarget) {
+ return this._isShown ? this.hide() : this.show(relatedTarget);
+ }
+ show(relatedTarget) {
+ if (this._isShown || this._isTransitioning) {
+ return;
+ }
+ const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, {
+ relatedTarget
+ });
+ if (showEvent.defaultPrevented) {
+ return;
+ }
+ this._isShown = true;
+ this._isTransitioning = true;
+ this._scrollBar.hide();
+ document.body.classList.add(CLASS_NAME_OPEN);
+ this._adjustDialog();
+ this._backdrop.show(() => this._showElement(relatedTarget));
+ }
+ hide() {
+ if (!this._isShown || this._isTransitioning) {
+ return;
+ }
+ const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4);
+ if (hideEvent.defaultPrevented) {
+ return;
+ }
+ this._isShown = false;
+ this._isTransitioning = true;
+ this._focustrap.deactivate();
+ this._element.classList.remove(CLASS_NAME_SHOW$4);
+ this._queueCallback(() => this._hideModal(), this._element, this._isAnimated());
+ }
+ dispose() {
+ EventHandler.off(window, EVENT_KEY$4);
+ EventHandler.off(this._dialog, EVENT_KEY$4);
+ this._backdrop.dispose();
+ this._focustrap.deactivate();
+ super.dispose();
+ }
+ handleUpdate() {
+ this._adjustDialog();
+ }
+
+ // Private
+ _initializeBackDrop() {
+ return new Backdrop({
+ isVisible: Boolean(this._config.backdrop),
+ // 'static' option will be translated to true, and booleans will keep their value,
+ isAnimated: this._isAnimated()
+ });
+ }
+ _initializeFocusTrap() {
+ return new FocusTrap({
+ trapElement: this._element
+ });
+ }
+ _showElement(relatedTarget) {
+ // try to append dynamic modal
+ if (!document.body.contains(this._element)) {
+ document.body.append(this._element);
+ }
+ this._element.style.display = 'block';
+ this._element.removeAttribute('aria-hidden');
+ this._element.setAttribute('aria-modal', true);
+ this._element.setAttribute('role', 'dialog');
+ this._element.scrollTop = 0;
+ const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog);
+ if (modalBody) {
+ modalBody.scrollTop = 0;
+ }
+ reflow(this._element);
+ this._element.classList.add(CLASS_NAME_SHOW$4);
+ const transitionComplete = () => {
+ if (this._config.focus) {
+ this._focustrap.activate();
+ }
+ this._isTransitioning = false;
+ EventHandler.trigger(this._element, EVENT_SHOWN$4, {
+ relatedTarget
+ });
+ };
+ this._queueCallback(transitionComplete, this._dialog, this._isAnimated());
+ }
+ _addEventListeners() {
+ EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => {
+ if (event.key !== ESCAPE_KEY$1) {
+ return;
+ }
+ if (this._config.keyboard) {
+ this.hide();
+ return;
+ }
+ this._triggerBackdropTransition();
+ });
+ EventHandler.on(window, EVENT_RESIZE$1, () => {
+ if (this._isShown && !this._isTransitioning) {
+ this._adjustDialog();
+ }
+ });
+ EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {
+ // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks
+ EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {
+ if (this._element !== event.target || this._element !== event2.target) {
+ return;
+ }
+ if (this._config.backdrop === 'static') {
+ this._triggerBackdropTransition();
+ return;
+ }
+ if (this._config.backdrop) {
+ this.hide();
+ }
+ });
+ });
+ }
+ _hideModal() {
+ this._element.style.display = 'none';
+ this._element.setAttribute('aria-hidden', true);
+ this._element.removeAttribute('aria-modal');
+ this._element.removeAttribute('role');
+ this._isTransitioning = false;
+ this._backdrop.hide(() => {
+ document.body.classList.remove(CLASS_NAME_OPEN);
+ this._resetAdjustments();
+ this._scrollBar.reset();
+ EventHandler.trigger(this._element, EVENT_HIDDEN$4);
+ });
+ }
+ _isAnimated() {
+ return this._element.classList.contains(CLASS_NAME_FADE$3);
+ }
+ _triggerBackdropTransition() {
+ const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1);
+ if (hideEvent.defaultPrevented) {
+ return;
+ }
+ const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
+ const initialOverflowY = this._element.style.overflowY;
+ // return if the following background transition hasn't yet completed
+ if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {
+ return;
+ }
+ if (!isModalOverflowing) {
+ this._element.style.overflowY = 'hidden';
+ }
+ this._element.classList.add(CLASS_NAME_STATIC);
+ this._queueCallback(() => {
+ this._element.classList.remove(CLASS_NAME_STATIC);
+ this._queueCallback(() => {
+ this._element.style.overflowY = initialOverflowY;
+ }, this._dialog);
+ }, this._dialog);
+ this._element.focus();
+ }
+
+ /**
+ * The following methods are used to handle overflowing modals
+ */
+
+ _adjustDialog() {
+ const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
+ const scrollbarWidth = this._scrollBar.getWidth();
+ const isBodyOverflowing = scrollbarWidth > 0;
+ if (isBodyOverflowing && !isModalOverflowing) {
+ const property = isRTL() ? 'paddingLeft' : 'paddingRight';
+ this._element.style[property] = `${scrollbarWidth}px`;
+ }
+ if (!isBodyOverflowing && isModalOverflowing) {
+ const property = isRTL() ? 'paddingRight' : 'paddingLeft';
+ this._element.style[property] = `${scrollbarWidth}px`;
+ }
+ }
+ _resetAdjustments() {
+ this._element.style.paddingLeft = '';
+ this._element.style.paddingRight = '';
+ }
+
+ // Static
+ static jQueryInterface(config, relatedTarget) {
+ return this.each(function () {
+ const data = Modal.getOrCreateInstance(this, config);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config](relatedTarget);
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) {
+ const target = SelectorEngine.getElementFromSelector(this);
+ if (['A', 'AREA'].includes(this.tagName)) {
+ event.preventDefault();
+ }
+ EventHandler.one(target, EVENT_SHOW$4, showEvent => {
+ if (showEvent.defaultPrevented) {
+ // only register focus restorer if modal will actually get shown
+ return;
+ }
+ EventHandler.one(target, EVENT_HIDDEN$4, () => {
+ if (isVisible(this)) {
+ this.focus();
+ }
+ });
+ });
+
+ // avoid conflict when clicking modal toggler while another one is open
+ const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1);
+ if (alreadyOpen) {
+ Modal.getInstance(alreadyOpen).hide();
+ }
+ const data = Modal.getOrCreateInstance(target);
+ data.toggle(this);
+ });
+ enableDismissTrigger(Modal);
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Modal);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap offcanvas.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$6 = 'offcanvas';
+ const DATA_KEY$3 = 'bs.offcanvas';
+ const EVENT_KEY$3 = `.${DATA_KEY$3}`;
+ const DATA_API_KEY$1 = '.data-api';
+ const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`;
+ const ESCAPE_KEY = 'Escape';
+ const CLASS_NAME_SHOW$3 = 'show';
+ const CLASS_NAME_SHOWING$1 = 'showing';
+ const CLASS_NAME_HIDING = 'hiding';
+ const CLASS_NAME_BACKDROP = 'offcanvas-backdrop';
+ const OPEN_SELECTOR = '.offcanvas.show';
+ const EVENT_SHOW$3 = `show${EVENT_KEY$3}`;
+ const EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`;
+ const EVENT_HIDE$3 = `hide${EVENT_KEY$3}`;
+ const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`;
+ const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`;
+ const EVENT_RESIZE = `resize${EVENT_KEY$3}`;
+ const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`;
+ const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`;
+ const SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle="offcanvas"]';
+ const Default$5 = {
+ backdrop: true,
+ keyboard: true,
+ scroll: false
+ };
+ const DefaultType$5 = {
+ backdrop: '(boolean|string)',
+ keyboard: 'boolean',
+ scroll: 'boolean'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Offcanvas extends BaseComponent {
+ constructor(element, config) {
+ super(element, config);
+ this._isShown = false;
+ this._backdrop = this._initializeBackDrop();
+ this._focustrap = this._initializeFocusTrap();
+ this._addEventListeners();
+ }
+
+ // Getters
+ static get Default() {
+ return Default$5;
+ }
+ static get DefaultType() {
+ return DefaultType$5;
+ }
+ static get NAME() {
+ return NAME$6;
+ }
+
+ // Public
+ toggle(relatedTarget) {
+ return this._isShown ? this.hide() : this.show(relatedTarget);
+ }
+ show(relatedTarget) {
+ if (this._isShown) {
+ return;
+ }
+ const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, {
+ relatedTarget
+ });
+ if (showEvent.defaultPrevented) {
+ return;
+ }
+ this._isShown = true;
+ this._backdrop.show();
+ if (!this._config.scroll) {
+ new ScrollBarHelper().hide();
+ }
+ this._element.setAttribute('aria-modal', true);
+ this._element.setAttribute('role', 'dialog');
+ this._element.classList.add(CLASS_NAME_SHOWING$1);
+ const completeCallBack = () => {
+ if (!this._config.scroll || this._config.backdrop) {
+ this._focustrap.activate();
+ }
+ this._element.classList.add(CLASS_NAME_SHOW$3);
+ this._element.classList.remove(CLASS_NAME_SHOWING$1);
+ EventHandler.trigger(this._element, EVENT_SHOWN$3, {
+ relatedTarget
+ });
+ };
+ this._queueCallback(completeCallBack, this._element, true);
+ }
+ hide() {
+ if (!this._isShown) {
+ return;
+ }
+ const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3);
+ if (hideEvent.defaultPrevented) {
+ return;
+ }
+ this._focustrap.deactivate();
+ this._element.blur();
+ this._isShown = false;
+ this._element.classList.add(CLASS_NAME_HIDING);
+ this._backdrop.hide();
+ const completeCallback = () => {
+ this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING);
+ this._element.removeAttribute('aria-modal');
+ this._element.removeAttribute('role');
+ if (!this._config.scroll) {
+ new ScrollBarHelper().reset();
+ }
+ EventHandler.trigger(this._element, EVENT_HIDDEN$3);
+ };
+ this._queueCallback(completeCallback, this._element, true);
+ }
+ dispose() {
+ this._backdrop.dispose();
+ this._focustrap.deactivate();
+ super.dispose();
+ }
+
+ // Private
+ _initializeBackDrop() {
+ const clickCallback = () => {
+ if (this._config.backdrop === 'static') {
+ EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
+ return;
+ }
+ this.hide();
+ };
+
+ // 'static' option will be translated to true, and booleans will keep their value
+ const isVisible = Boolean(this._config.backdrop);
+ return new Backdrop({
+ className: CLASS_NAME_BACKDROP,
+ isVisible,
+ isAnimated: true,
+ rootElement: this._element.parentNode,
+ clickCallback: isVisible ? clickCallback : null
+ });
+ }
+ _initializeFocusTrap() {
+ return new FocusTrap({
+ trapElement: this._element
+ });
+ }
+ _addEventListeners() {
+ EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
+ if (event.key !== ESCAPE_KEY) {
+ return;
+ }
+ if (this._config.keyboard) {
+ this.hide();
+ return;
+ }
+ EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
+ });
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Offcanvas.getOrCreateInstance(this, config);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config](this);
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) {
+ const target = SelectorEngine.getElementFromSelector(this);
+ if (['A', 'AREA'].includes(this.tagName)) {
+ event.preventDefault();
+ }
+ if (isDisabled(this)) {
+ return;
+ }
+ EventHandler.one(target, EVENT_HIDDEN$3, () => {
+ // focus on trigger when it is closed
+ if (isVisible(this)) {
+ this.focus();
+ }
+ });
+
+ // avoid conflict when clicking a toggler of an offcanvas, while another is open
+ const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);
+ if (alreadyOpen && alreadyOpen !== target) {
+ Offcanvas.getInstance(alreadyOpen).hide();
+ }
+ const data = Offcanvas.getOrCreateInstance(target);
+ data.toggle(this);
+ });
+ EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => {
+ for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {
+ Offcanvas.getOrCreateInstance(selector).show();
+ }
+ });
+ EventHandler.on(window, EVENT_RESIZE, () => {
+ for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {
+ if (getComputedStyle(element).position !== 'fixed') {
+ Offcanvas.getOrCreateInstance(element).hide();
+ }
+ }
+ });
+ enableDismissTrigger(Offcanvas);
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Offcanvas);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/sanitizer.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+ // js-docs-start allow-list
+ const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
+ const DefaultAllowlist = {
+ // Global attributes allowed on any supplied element below.
+ '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
+ a: ['target', 'href', 'title', 'rel'],
+ area: [],
+ b: [],
+ br: [],
+ col: [],
+ code: [],
+ div: [],
+ em: [],
+ hr: [],
+ h1: [],
+ h2: [],
+ h3: [],
+ h4: [],
+ h5: [],
+ h6: [],
+ i: [],
+ img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
+ li: [],
+ ol: [],
+ p: [],
+ pre: [],
+ s: [],
+ small: [],
+ span: [],
+ sub: [],
+ sup: [],
+ strong: [],
+ u: [],
+ ul: []
+ };
+ // js-docs-end allow-list
+
+ const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
+
+ /**
+ * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
+ * contexts.
+ *
+ * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
+ */
+ // eslint-disable-next-line unicorn/better-regex
+ const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
+ const allowedAttribute = (attribute, allowedAttributeList) => {
+ const attributeName = attribute.nodeName.toLowerCase();
+ if (allowedAttributeList.includes(attributeName)) {
+ if (uriAttributes.has(attributeName)) {
+ return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));
+ }
+ return true;
+ }
+
+ // Check if a regular expression validates the attribute.
+ return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
+ };
+ function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
+ if (!unsafeHtml.length) {
+ return unsafeHtml;
+ }
+ if (sanitizeFunction && typeof sanitizeFunction === 'function') {
+ return sanitizeFunction(unsafeHtml);
+ }
+ const domParser = new window.DOMParser();
+ const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
+ const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
+ for (const element of elements) {
+ const elementName = element.nodeName.toLowerCase();
+ if (!Object.keys(allowList).includes(elementName)) {
+ element.remove();
+ continue;
+ }
+ const attributeList = [].concat(...element.attributes);
+ const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
+ for (const attribute of attributeList) {
+ if (!allowedAttribute(attribute, allowedAttributes)) {
+ element.removeAttribute(attribute.nodeName);
+ }
+ }
+ }
+ return createdDocument.body.innerHTML;
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/template-factory.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$5 = 'TemplateFactory';
+ const Default$4 = {
+ allowList: DefaultAllowlist,
+ content: {},
+ // { selector : text , selector2 : text2 , }
+ extraClass: '',
+ html: false,
+ sanitize: true,
+ sanitizeFn: null,
+ template: '<div></div>'
+ };
+ const DefaultType$4 = {
+ allowList: 'object',
+ content: 'object',
+ extraClass: '(string|function)',
+ html: 'boolean',
+ sanitize: 'boolean',
+ sanitizeFn: '(null|function)',
+ template: 'string'
+ };
+ const DefaultContentType = {
+ entry: '(string|element|function|null)',
+ selector: '(string|element)'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class TemplateFactory extends Config {
+ constructor(config) {
+ super();
+ this._config = this._getConfig(config);
+ }
+
+ // Getters
+ static get Default() {
+ return Default$4;
+ }
+ static get DefaultType() {
+ return DefaultType$4;
+ }
+ static get NAME() {
+ return NAME$5;
+ }
+
+ // Public
+ getContent() {
+ return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);
+ }
+ hasContent() {
+ return this.getContent().length > 0;
+ }
+ changeContent(content) {
+ this._checkContent(content);
+ this._config.content = {
+ ...this._config.content,
+ ...content
+ };
+ return this;
+ }
+ toHtml() {
+ const templateWrapper = document.createElement('div');
+ templateWrapper.innerHTML = this._maybeSanitize(this._config.template);
+ for (const [selector, text] of Object.entries(this._config.content)) {
+ this._setContent(templateWrapper, text, selector);
+ }
+ const template = templateWrapper.children[0];
+ const extraClass = this._resolvePossibleFunction(this._config.extraClass);
+ if (extraClass) {
+ template.classList.add(...extraClass.split(' '));
+ }
+ return template;
+ }
+
+ // Private
+ _typeCheckConfig(config) {
+ super._typeCheckConfig(config);
+ this._checkContent(config.content);
+ }
+ _checkContent(arg) {
+ for (const [selector, content] of Object.entries(arg)) {
+ super._typeCheckConfig({
+ selector,
+ entry: content
+ }, DefaultContentType);
+ }
+ }
+ _setContent(template, content, selector) {
+ const templateElement = SelectorEngine.findOne(selector, template);
+ if (!templateElement) {
+ return;
+ }
+ content = this._resolvePossibleFunction(content);
+ if (!content) {
+ templateElement.remove();
+ return;
+ }
+ if (isElement$1(content)) {
+ this._putElementInTemplate(getElement(content), templateElement);
+ return;
+ }
+ if (this._config.html) {
+ templateElement.innerHTML = this._maybeSanitize(content);
+ return;
+ }
+ templateElement.textContent = content;
+ }
+ _maybeSanitize(arg) {
+ return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;
+ }
+ _resolvePossibleFunction(arg) {
+ return execute(arg, [this]);
+ }
+ _putElementInTemplate(element, templateElement) {
+ if (this._config.html) {
+ templateElement.innerHTML = '';
+ templateElement.append(element);
+ return;
+ }
+ templateElement.textContent = element.textContent;
+ }
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap tooltip.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$4 = 'tooltip';
+ const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']);
+ const CLASS_NAME_FADE$2 = 'fade';
+ const CLASS_NAME_MODAL = 'modal';
+ const CLASS_NAME_SHOW$2 = 'show';
+ const SELECTOR_TOOLTIP_INNER = '.tooltip-inner';
+ const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;
+ const EVENT_MODAL_HIDE = 'hide.bs.modal';
+ const TRIGGER_HOVER = 'hover';
+ const TRIGGER_FOCUS = 'focus';
+ const TRIGGER_CLICK = 'click';
+ const TRIGGER_MANUAL = 'manual';
+ const EVENT_HIDE$2 = 'hide';
+ const EVENT_HIDDEN$2 = 'hidden';
+ const EVENT_SHOW$2 = 'show';
+ const EVENT_SHOWN$2 = 'shown';
+ const EVENT_INSERTED = 'inserted';
+ const EVENT_CLICK$1 = 'click';
+ const EVENT_FOCUSIN$1 = 'focusin';
+ const EVENT_FOCUSOUT$1 = 'focusout';
+ const EVENT_MOUSEENTER = 'mouseenter';
+ const EVENT_MOUSELEAVE = 'mouseleave';
+ const AttachmentMap = {
+ AUTO: 'auto',
+ TOP: 'top',
+ RIGHT: isRTL() ? 'left' : 'right',
+ BOTTOM: 'bottom',
+ LEFT: isRTL() ? 'right' : 'left'
+ };
+ const Default$3 = {
+ allowList: DefaultAllowlist,
+ animation: true,
+ boundary: 'clippingParents',
+ container: false,
+ customClass: '',
+ delay: 0,
+ fallbackPlacements: ['top', 'right', 'bottom', 'left'],
+ html: false,
+ offset: [0, 6],
+ placement: 'top',
+ popperConfig: null,
+ sanitize: true,
+ sanitizeFn: null,
+ selector: false,
+ template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>',
+ title: '',
+ trigger: 'hover focus'
+ };
+ const DefaultType$3 = {
+ allowList: 'object',
+ animation: 'boolean',
+ boundary: '(string|element)',
+ container: '(string|element|boolean)',
+ customClass: '(string|function)',
+ delay: '(number|object)',
+ fallbackPlacements: 'array',
+ html: 'boolean',
+ offset: '(array|string|function)',
+ placement: '(string|function)',
+ popperConfig: '(null|object|function)',
+ sanitize: 'boolean',
+ sanitizeFn: '(null|function)',
+ selector: '(string|boolean)',
+ template: 'string',
+ title: '(string|element|function)',
+ trigger: 'string'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Tooltip extends BaseComponent {
+ constructor(element, config) {
+ if (typeof Popper === 'undefined') {
+ throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)');
+ }
+ super(element, config);
+
+ // Private
+ this._isEnabled = true;
+ this._timeout = 0;
+ this._isHovered = null;
+ this._activeTrigger = {};
+ this._popper = null;
+ this._templateFactory = null;
+ this._newContent = null;
+
+ // Protected
+ this.tip = null;
+ this._setListeners();
+ if (!this._config.selector) {
+ this._fixTitle();
+ }
+ }
+
+ // Getters
+ static get Default() {
+ return Default$3;
+ }
+ static get DefaultType() {
+ return DefaultType$3;
+ }
+ static get NAME() {
+ return NAME$4;
+ }
+
+ // Public
+ enable() {
+ this._isEnabled = true;
+ }
+ disable() {
+ this._isEnabled = false;
+ }
+ toggleEnabled() {
+ this._isEnabled = !this._isEnabled;
+ }
+ toggle() {
+ if (!this._isEnabled) {
+ return;
+ }
+ this._activeTrigger.click = !this._activeTrigger.click;
+ if (this._isShown()) {
+ this._leave();
+ return;
+ }
+ this._enter();
+ }
+ dispose() {
+ clearTimeout(this._timeout);
+ EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);
+ if (this._element.getAttribute('data-bs-original-title')) {
+ this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'));
+ }
+ this._disposePopper();
+ super.dispose();
+ }
+ show() {
+ if (this._element.style.display === 'none') {
+ throw new Error('Please use show on visible elements');
+ }
+ if (!(this._isWithContent() && this._isEnabled)) {
+ return;
+ }
+ const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2));
+ const shadowRoot = findShadowRoot(this._element);
+ const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element);
+ if (showEvent.defaultPrevented || !isInTheDom) {
+ return;
+ }
+
+ // TODO: v6 remove this or make it optional
+ this._disposePopper();
+ const tip = this._getTipElement();
+ this._element.setAttribute('aria-describedby', tip.getAttribute('id'));
+ const {
+ container
+ } = this._config;
+ if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
+ container.append(tip);
+ EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED));
+ }
+ this._popper = this._createPopper(tip);
+ tip.classList.add(CLASS_NAME_SHOW$2);
+
+ // If this is a touch-enabled device we add extra
+ // empty mouseover listeners to the body's immediate children;
+ // only needed because of broken event delegation on iOS
+ // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+ if ('ontouchstart' in document.documentElement) {
+ for (const element of [].concat(...document.body.children)) {
+ EventHandler.on(element, 'mouseover', noop);
+ }
+ }
+ const complete = () => {
+ EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2));
+ if (this._isHovered === false) {
+ this._leave();
+ }
+ this._isHovered = false;
+ };
+ this._queueCallback(complete, this.tip, this._isAnimated());
+ }
+ hide() {
+ if (!this._isShown()) {
+ return;
+ }
+ const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2));
+ if (hideEvent.defaultPrevented) {
+ return;
+ }
+ const tip = this._getTipElement();
+ tip.classList.remove(CLASS_NAME_SHOW$2);
+
+ // If this is a touch-enabled device we remove the extra
+ // empty mouseover listeners we added for iOS support
+ if ('ontouchstart' in document.documentElement) {
+ for (const element of [].concat(...document.body.children)) {
+ EventHandler.off(element, 'mouseover', noop);
+ }
+ }
+ this._activeTrigger[TRIGGER_CLICK] = false;
+ this._activeTrigger[TRIGGER_FOCUS] = false;
+ this._activeTrigger[TRIGGER_HOVER] = false;
+ this._isHovered = null; // it is a trick to support manual triggering
+
+ const complete = () => {
+ if (this._isWithActiveTrigger()) {
+ return;
+ }
+ if (!this._isHovered) {
+ this._disposePopper();
+ }
+ this._element.removeAttribute('aria-describedby');
+ EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2));
+ };
+ this._queueCallback(complete, this.tip, this._isAnimated());
+ }
+ update() {
+ if (this._popper) {
+ this._popper.update();
+ }
+ }
+
+ // Protected
+ _isWithContent() {
+ return Boolean(this._getTitle());
+ }
+ _getTipElement() {
+ if (!this.tip) {
+ this.tip = this._createTipElement(this._newContent || this._getContentForTemplate());
+ }
+ return this.tip;
+ }
+ _createTipElement(content) {
+ const tip = this._getTemplateFactory(content).toHtml();
+
+ // TODO: remove this check in v6
+ if (!tip) {
+ return null;
+ }
+ tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2);
+ // TODO: v6 the following can be achieved with CSS only
+ tip.classList.add(`bs-${this.constructor.NAME}-auto`);
+ const tipId = getUID(this.constructor.NAME).toString();
+ tip.setAttribute('id', tipId);
+ if (this._isAnimated()) {
+ tip.classList.add(CLASS_NAME_FADE$2);
+ }
+ return tip;
+ }
+ setContent(content) {
+ this._newContent = content;
+ if (this._isShown()) {
+ this._disposePopper();
+ this.show();
+ }
+ }
+ _getTemplateFactory(content) {
+ if (this._templateFactory) {
+ this._templateFactory.changeContent(content);
+ } else {
+ this._templateFactory = new TemplateFactory({
+ ...this._config,
+ // the `content` var has to be after `this._config`
+ // to override config.content in case of popover
+ content,
+ extraClass: this._resolvePossibleFunction(this._config.customClass)
+ });
+ }
+ return this._templateFactory;
+ }
+ _getContentForTemplate() {
+ return {
+ [SELECTOR_TOOLTIP_INNER]: this._getTitle()
+ };
+ }
+ _getTitle() {
+ return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title');
+ }
+
+ // Private
+ _initializeOnDelegatedTarget(event) {
+ return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());
+ }
+ _isAnimated() {
+ return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2);
+ }
+ _isShown() {
+ return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2);
+ }
+ _createPopper(tip) {
+ const placement = execute(this._config.placement, [this, tip, this._element]);
+ const attachment = AttachmentMap[placement.toUpperCase()];
+ return createPopper(this._element, tip, this._getPopperConfig(attachment));
+ }
+ _getOffset() {
+ const {
+ offset
+ } = this._config;
+ if (typeof offset === 'string') {
+ return offset.split(',').map(value => Number.parseInt(value, 10));
+ }
+ if (typeof offset === 'function') {
+ return popperData => offset(popperData, this._element);
+ }
+ return offset;
+ }
+ _resolvePossibleFunction(arg) {
+ return execute(arg, [this._element]);
+ }
+ _getPopperConfig(attachment) {
+ const defaultBsPopperConfig = {
+ placement: attachment,
+ modifiers: [{
+ name: 'flip',
+ options: {
+ fallbackPlacements: this._config.fallbackPlacements
+ }
+ }, {
+ name: 'offset',
+ options: {
+ offset: this._getOffset()
+ }
+ }, {
+ name: 'preventOverflow',
+ options: {
+ boundary: this._config.boundary
+ }
+ }, {
+ name: 'arrow',
+ options: {
+ element: `.${this.constructor.NAME}-arrow`
+ }
+ }, {
+ name: 'preSetPlacement',
+ enabled: true,
+ phase: 'beforeMain',
+ fn: data => {
+ // Pre-set Popper's placement attribute in order to read the arrow sizes properly.
+ // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement
+ this._getTipElement().setAttribute('data-popper-placement', data.state.placement);
+ }
+ }]
+ };
+ return {
+ ...defaultBsPopperConfig,
+ ...execute(this._config.popperConfig, [defaultBsPopperConfig])
+ };
+ }
+ _setListeners() {
+ const triggers = this._config.trigger.split(' ');
+ for (const trigger of triggers) {
+ if (trigger === 'click') {
+ EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => {
+ const context = this._initializeOnDelegatedTarget(event);
+ context.toggle();
+ });
+ } else if (trigger !== TRIGGER_MANUAL) {
+ const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1);
+ const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1);
+ EventHandler.on(this._element, eventIn, this._config.selector, event => {
+ const context = this._initializeOnDelegatedTarget(event);
+ context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;
+ context._enter();
+ });
+ EventHandler.on(this._element, eventOut, this._config.selector, event => {
+ const context = this._initializeOnDelegatedTarget(event);
+ context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);
+ context._leave();
+ });
+ }
+ }
+ this._hideModalHandler = () => {
+ if (this._element) {
+ this.hide();
+ }
+ };
+ EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);
+ }
+ _fixTitle() {
+ const title = this._element.getAttribute('title');
+ if (!title) {
+ return;
+ }
+ if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {
+ this._element.setAttribute('aria-label', title);
+ }
+ this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility
+ this._element.removeAttribute('title');
+ }
+ _enter() {
+ if (this._isShown() || this._isHovered) {
+ this._isHovered = true;
+ return;
+ }
+ this._isHovered = true;
+ this._setTimeout(() => {
+ if (this._isHovered) {
+ this.show();
+ }
+ }, this._config.delay.show);
+ }
+ _leave() {
+ if (this._isWithActiveTrigger()) {
+ return;
+ }
+ this._isHovered = false;
+ this._setTimeout(() => {
+ if (!this._isHovered) {
+ this.hide();
+ }
+ }, this._config.delay.hide);
+ }
+ _setTimeout(handler, timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = setTimeout(handler, timeout);
+ }
+ _isWithActiveTrigger() {
+ return Object.values(this._activeTrigger).includes(true);
+ }
+ _getConfig(config) {
+ const dataAttributes = Manipulator.getDataAttributes(this._element);
+ for (const dataAttribute of Object.keys(dataAttributes)) {
+ if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {
+ delete dataAttributes[dataAttribute];
+ }
+ }
+ config = {
+ ...dataAttributes,
+ ...(typeof config === 'object' && config ? config : {})
+ };
+ config = this._mergeConfigObj(config);
+ config = this._configAfterMerge(config);
+ this._typeCheckConfig(config);
+ return config;
+ }
+ _configAfterMerge(config) {
+ config.container = config.container === false ? document.body : getElement(config.container);
+ if (typeof config.delay === 'number') {
+ config.delay = {
+ show: config.delay,
+ hide: config.delay
+ };
+ }
+ if (typeof config.title === 'number') {
+ config.title = config.title.toString();
+ }
+ if (typeof config.content === 'number') {
+ config.content = config.content.toString();
+ }
+ return config;
+ }
+ _getDelegateConfig() {
+ const config = {};
+ for (const [key, value] of Object.entries(this._config)) {
+ if (this.constructor.Default[key] !== value) {
+ config[key] = value;
+ }
+ }
+ config.selector = false;
+ config.trigger = 'manual';
+
+ // In the future can be replaced with:
+ // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])
+ // `Object.fromEntries(keysWithDifferentValues)`
+ return config;
+ }
+ _disposePopper() {
+ if (this._popper) {
+ this._popper.destroy();
+ this._popper = null;
+ }
+ if (this.tip) {
+ this.tip.remove();
+ this.tip = null;
+ }
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Tooltip.getOrCreateInstance(this, config);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config]();
+ });
+ }
+ }
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Tooltip);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap popover.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$3 = 'popover';
+ const SELECTOR_TITLE = '.popover-header';
+ const SELECTOR_CONTENT = '.popover-body';
+ const Default$2 = {
+ ...Tooltip.Default,
+ content: '',
+ offset: [0, 8],
+ placement: 'right',
+ template: '<div class="popover" role="tooltip">' + '<div class="popover-arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + '</div>',
+ trigger: 'click'
+ };
+ const DefaultType$2 = {
+ ...Tooltip.DefaultType,
+ content: '(null|string|element|function)'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Popover extends Tooltip {
+ // Getters
+ static get Default() {
+ return Default$2;
+ }
+ static get DefaultType() {
+ return DefaultType$2;
+ }
+ static get NAME() {
+ return NAME$3;
+ }
+
+ // Overrides
+ _isWithContent() {
+ return this._getTitle() || this._getContent();
+ }
+
+ // Private
+ _getContentForTemplate() {
+ return {
+ [SELECTOR_TITLE]: this._getTitle(),
+ [SELECTOR_CONTENT]: this._getContent()
+ };
+ }
+ _getContent() {
+ return this._resolvePossibleFunction(this._config.content);
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Popover.getOrCreateInstance(this, config);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config]();
+ });
+ }
+ }
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Popover);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap scrollspy.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$2 = 'scrollspy';
+ const DATA_KEY$2 = 'bs.scrollspy';
+ const EVENT_KEY$2 = `.${DATA_KEY$2}`;
+ const DATA_API_KEY = '.data-api';
+ const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`;
+ const EVENT_CLICK = `click${EVENT_KEY$2}`;
+ const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`;
+ const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
+ const CLASS_NAME_ACTIVE$1 = 'active';
+ const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]';
+ const SELECTOR_TARGET_LINKS = '[href]';
+ const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
+ const SELECTOR_NAV_LINKS = '.nav-link';
+ const SELECTOR_NAV_ITEMS = '.nav-item';
+ const SELECTOR_LIST_ITEMS = '.list-group-item';
+ const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;
+ const SELECTOR_DROPDOWN = '.dropdown';
+ const SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle';
+ const Default$1 = {
+ offset: null,
+ // TODO: v6 @deprecated, keep it for backwards compatibility reasons
+ rootMargin: '0px 0px -25%',
+ smoothScroll: false,
+ target: null,
+ threshold: [0.1, 0.5, 1]
+ };
+ const DefaultType$1 = {
+ offset: '(number|null)',
+ // TODO v6 @deprecated, keep it for backwards compatibility reasons
+ rootMargin: 'string',
+ smoothScroll: 'boolean',
+ target: 'element',
+ threshold: 'array'
+ };
+
+ /**
+ * Class definition
+ */
+
+ class ScrollSpy extends BaseComponent {
+ constructor(element, config) {
+ super(element, config);
+
+ // this._element is the observablesContainer and config.target the menu links wrapper
+ this._targetLinks = new Map();
+ this._observableSections = new Map();
+ this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;
+ this._activeTarget = null;
+ this._observer = null;
+ this._previousScrollData = {
+ visibleEntryTop: 0,
+ parentScrollTop: 0
+ };
+ this.refresh(); // initialize
+ }
+
+ // Getters
+ static get Default() {
+ return Default$1;
+ }
+ static get DefaultType() {
+ return DefaultType$1;
+ }
+ static get NAME() {
+ return NAME$2;
+ }
+
+ // Public
+ refresh() {
+ this._initializeTargetsAndObservables();
+ this._maybeEnableSmoothScroll();
+ if (this._observer) {
+ this._observer.disconnect();
+ } else {
+ this._observer = this._getNewObserver();
+ }
+ for (const section of this._observableSections.values()) {
+ this._observer.observe(section);
+ }
+ }
+ dispose() {
+ this._observer.disconnect();
+ super.dispose();
+ }
+
+ // Private
+ _configAfterMerge(config) {
+ // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
+ config.target = getElement(config.target) || document.body;
+
+ // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
+ config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;
+ if (typeof config.threshold === 'string') {
+ config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));
+ }
+ return config;
+ }
+ _maybeEnableSmoothScroll() {
+ if (!this._config.smoothScroll) {
+ return;
+ }
+
+ // unregister any previous listeners
+ EventHandler.off(this._config.target, EVENT_CLICK);
+ EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {
+ const observableSection = this._observableSections.get(event.target.hash);
+ if (observableSection) {
+ event.preventDefault();
+ const root = this._rootElement || window;
+ const height = observableSection.offsetTop - this._element.offsetTop;
+ if (root.scrollTo) {
+ root.scrollTo({
+ top: height,
+ behavior: 'smooth'
+ });
+ return;
+ }
+
+ // Chrome 60 doesn't support `scrollTo`
+ root.scrollTop = height;
+ }
+ });
+ }
+ _getNewObserver() {
+ const options = {
+ root: this._rootElement,
+ threshold: this._config.threshold,
+ rootMargin: this._config.rootMargin
+ };
+ return new IntersectionObserver(entries => this._observerCallback(entries), options);
+ }
+
+ // The logic of selection
+ _observerCallback(entries) {
+ const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);
+ const activate = entry => {
+ this._previousScrollData.visibleEntryTop = entry.target.offsetTop;
+ this._process(targetElement(entry));
+ };
+ const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;
+ const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;
+ this._previousScrollData.parentScrollTop = parentScrollTop;
+ for (const entry of entries) {
+ if (!entry.isIntersecting) {
+ this._activeTarget = null;
+ this._clearActiveClass(targetElement(entry));
+ continue;
+ }
+ const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop;
+ // if we are scrolling down, pick the bigger offsetTop
+ if (userScrollsDown && entryIsLowerThanPrevious) {
+ activate(entry);
+ // if parent isn't scrolled, let's keep the first visible item, breaking the iteration
+ if (!parentScrollTop) {
+ return;
+ }
+ continue;
+ }
+
+ // if we are scrolling up, pick the smallest offsetTop
+ if (!userScrollsDown && !entryIsLowerThanPrevious) {
+ activate(entry);
+ }
+ }
+ }
+ _initializeTargetsAndObservables() {
+ this._targetLinks = new Map();
+ this._observableSections = new Map();
+ const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);
+ for (const anchor of targetLinks) {
+ // ensure that the anchor has an id and is not disabled
+ if (!anchor.hash || isDisabled(anchor)) {
+ continue;
+ }
+ const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element);
+
+ // ensure that the observableSection exists & is visible
+ if (isVisible(observableSection)) {
+ this._targetLinks.set(decodeURI(anchor.hash), anchor);
+ this._observableSections.set(anchor.hash, observableSection);
+ }
+ }
+ }
+ _process(target) {
+ if (this._activeTarget === target) {
+ return;
+ }
+ this._clearActiveClass(this._config.target);
+ this._activeTarget = target;
+ target.classList.add(CLASS_NAME_ACTIVE$1);
+ this._activateParents(target);
+ EventHandler.trigger(this._element, EVENT_ACTIVATE, {
+ relatedTarget: target
+ });
+ }
+ _activateParents(target) {
+ // Activate dropdown parents
+ if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
+ SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1);
+ return;
+ }
+ for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {
+ // Set triggered links parents as active
+ // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
+ for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {
+ item.classList.add(CLASS_NAME_ACTIVE$1);
+ }
+ }
+ }
+ _clearActiveClass(parent) {
+ parent.classList.remove(CLASS_NAME_ACTIVE$1);
+ const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE$1}`, parent);
+ for (const node of activeNodes) {
+ node.classList.remove(CLASS_NAME_ACTIVE$1);
+ }
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = ScrollSpy.getOrCreateInstance(this, config);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config]();
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => {
+ for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {
+ ScrollSpy.getOrCreateInstance(spy);
+ }
+ });
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(ScrollSpy);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap tab.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME$1 = 'tab';
+ const DATA_KEY$1 = 'bs.tab';
+ const EVENT_KEY$1 = `.${DATA_KEY$1}`;
+ const EVENT_HIDE$1 = `hide${EVENT_KEY$1}`;
+ const EVENT_HIDDEN$1 = `hidden${EVENT_KEY$1}`;
+ const EVENT_SHOW$1 = `show${EVENT_KEY$1}`;
+ const EVENT_SHOWN$1 = `shown${EVENT_KEY$1}`;
+ const EVENT_CLICK_DATA_API = `click${EVENT_KEY$1}`;
+ const EVENT_KEYDOWN = `keydown${EVENT_KEY$1}`;
+ const EVENT_LOAD_DATA_API = `load${EVENT_KEY$1}`;
+ const ARROW_LEFT_KEY = 'ArrowLeft';
+ const ARROW_RIGHT_KEY = 'ArrowRight';
+ const ARROW_UP_KEY = 'ArrowUp';
+ const ARROW_DOWN_KEY = 'ArrowDown';
+ const HOME_KEY = 'Home';
+ const END_KEY = 'End';
+ const CLASS_NAME_ACTIVE = 'active';
+ const CLASS_NAME_FADE$1 = 'fade';
+ const CLASS_NAME_SHOW$1 = 'show';
+ const CLASS_DROPDOWN = 'dropdown';
+ const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
+ const SELECTOR_DROPDOWN_MENU = '.dropdown-menu';
+ const NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)';
+ const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]';
+ const SELECTOR_OUTER = '.nav-item, .list-group-item';
+ const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
+ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // TODO: could only be `tab` in v6
+ const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
+ 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"]`;
+
+ /**
+ * Class definition
+ */
+
+ class Tab extends BaseComponent {
+ constructor(element) {
+ super(element);
+ this._parent = this._element.closest(SELECTOR_TAB_PANEL);
+ if (!this._parent) {
+ return;
+ // TODO: should throw exception in v6
+ // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
+ }
+
+ // Set up initial aria attributes
+ this._setInitialAttributes(this._parent, this._getChildren());
+ EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
+ }
+
+ // Getters
+ static get NAME() {
+ return NAME$1;
+ }
+
+ // Public
+ show() {
+ // Shows this elem and deactivate the active sibling if exists
+ const innerElem = this._element;
+ if (this._elemIsActive(innerElem)) {
+ return;
+ }
+
+ // Search for active tab on same parent to deactivate it
+ const active = this._getActiveElem();
+ const hideEvent = active ? EventHandler.trigger(active, EVENT_HIDE$1, {
+ relatedTarget: innerElem
+ }) : null;
+ const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW$1, {
+ relatedTarget: active
+ });
+ if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) {
+ return;
+ }
+ this._deactivate(active, innerElem);
+ this._activate(innerElem, active);
+ }
+
+ // Private
+ _activate(element, relatedElem) {
+ if (!element) {
+ return;
+ }
+ element.classList.add(CLASS_NAME_ACTIVE);
+ this._activate(SelectorEngine.getElementFromSelector(element)); // Search and activate/show the proper section
+
+ const complete = () => {
+ if (element.getAttribute('role') !== 'tab') {
+ element.classList.add(CLASS_NAME_SHOW$1);
+ return;
+ }
+ element.removeAttribute('tabindex');
+ element.setAttribute('aria-selected', true);
+ this._toggleDropDown(element, true);
+ EventHandler.trigger(element, EVENT_SHOWN$1, {
+ relatedTarget: relatedElem
+ });
+ };
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1));
+ }
+ _deactivate(element, relatedElem) {
+ if (!element) {
+ return;
+ }
+ element.classList.remove(CLASS_NAME_ACTIVE);
+ element.blur();
+ this._deactivate(SelectorEngine.getElementFromSelector(element)); // Search and deactivate the shown section too
+
+ const complete = () => {
+ if (element.getAttribute('role') !== 'tab') {
+ element.classList.remove(CLASS_NAME_SHOW$1);
+ return;
+ }
+ element.setAttribute('aria-selected', false);
+ element.setAttribute('tabindex', '-1');
+ this._toggleDropDown(element, false);
+ EventHandler.trigger(element, EVENT_HIDDEN$1, {
+ relatedTarget: relatedElem
+ });
+ };
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1));
+ }
+ _keydown(event) {
+ if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key)) {
+ return;
+ }
+ event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page
+ event.preventDefault();
+ const children = this._getChildren().filter(element => !isDisabled(element));
+ let nextActiveElement;
+ if ([HOME_KEY, END_KEY].includes(event.key)) {
+ nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1];
+ } else {
+ const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key);
+ nextActiveElement = getNextActiveElement(children, event.target, isNext, true);
+ }
+ if (nextActiveElement) {
+ nextActiveElement.focus({
+ preventScroll: true
+ });
+ Tab.getOrCreateInstance(nextActiveElement).show();
+ }
+ }
+ _getChildren() {
+ // collection of inner elements
+ return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent);
+ }
+ _getActiveElem() {
+ return this._getChildren().find(child => this._elemIsActive(child)) || null;
+ }
+ _setInitialAttributes(parent, children) {
+ this._setAttributeIfNotExists(parent, 'role', 'tablist');
+ for (const child of children) {
+ this._setInitialAttributesOnChild(child);
+ }
+ }
+ _setInitialAttributesOnChild(child) {
+ child = this._getInnerElement(child);
+ const isActive = this._elemIsActive(child);
+ const outerElem = this._getOuterElement(child);
+ child.setAttribute('aria-selected', isActive);
+ if (outerElem !== child) {
+ this._setAttributeIfNotExists(outerElem, 'role', 'presentation');
+ }
+ if (!isActive) {
+ child.setAttribute('tabindex', '-1');
+ }
+ this._setAttributeIfNotExists(child, 'role', 'tab');
+
+ // set attributes to the related panel too
+ this._setInitialAttributesOnTargetPanel(child);
+ }
+ _setInitialAttributesOnTargetPanel(child) {
+ const target = SelectorEngine.getElementFromSelector(child);
+ if (!target) {
+ return;
+ }
+ this._setAttributeIfNotExists(target, 'role', 'tabpanel');
+ if (child.id) {
+ this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`);
+ }
+ }
+ _toggleDropDown(element, open) {
+ const outerElem = this._getOuterElement(element);
+ if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
+ return;
+ }
+ const toggle = (selector, className) => {
+ const element = SelectorEngine.findOne(selector, outerElem);
+ if (element) {
+ element.classList.toggle(className, open);
+ }
+ };
+ toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE);
+ toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW$1);
+ outerElem.setAttribute('aria-expanded', open);
+ }
+ _setAttributeIfNotExists(element, attribute, value) {
+ if (!element.hasAttribute(attribute)) {
+ element.setAttribute(attribute, value);
+ }
+ }
+ _elemIsActive(elem) {
+ return elem.classList.contains(CLASS_NAME_ACTIVE);
+ }
+
+ // Try to get the inner element (usually the .nav-link)
+ _getInnerElement(elem) {
+ return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem);
+ }
+
+ // Try to get the outer element (usually the .nav-item)
+ _getOuterElement(elem) {
+ return elem.closest(SELECTOR_OUTER) || elem;
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Tab.getOrCreateInstance(this);
+ if (typeof config !== 'string') {
+ return;
+ }
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config]();
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+ if (['A', 'AREA'].includes(this.tagName)) {
+ event.preventDefault();
+ }
+ if (isDisabled(this)) {
+ return;
+ }
+ Tab.getOrCreateInstance(this).show();
+ });
+
+ /**
+ * Initialize on focus
+ */
+ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+ for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {
+ Tab.getOrCreateInstance(element);
+ }
+ });
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Tab);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap toast.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Constants
+ */
+
+ const NAME = 'toast';
+ const DATA_KEY = 'bs.toast';
+ const EVENT_KEY = `.${DATA_KEY}`;
+ const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`;
+ const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`;
+ const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
+ const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`;
+ const EVENT_HIDE = `hide${EVENT_KEY}`;
+ const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
+ const EVENT_SHOW = `show${EVENT_KEY}`;
+ const EVENT_SHOWN = `shown${EVENT_KEY}`;
+ const CLASS_NAME_FADE = 'fade';
+ const CLASS_NAME_HIDE = 'hide'; // @deprecated - kept here only for backwards compatibility
+ const CLASS_NAME_SHOW = 'show';
+ const CLASS_NAME_SHOWING = 'showing';
+ const DefaultType = {
+ animation: 'boolean',
+ autohide: 'boolean',
+ delay: 'number'
+ };
+ const Default = {
+ animation: true,
+ autohide: true,
+ delay: 5000
+ };
+
+ /**
+ * Class definition
+ */
+
+ class Toast extends BaseComponent {
+ constructor(element, config) {
+ super(element, config);
+ this._timeout = null;
+ this._hasMouseInteraction = false;
+ this._hasKeyboardInteraction = false;
+ this._setListeners();
+ }
+
+ // Getters
+ static get Default() {
+ return Default;
+ }
+ static get DefaultType() {
+ return DefaultType;
+ }
+ static get NAME() {
+ return NAME;
+ }
+
+ // Public
+ show() {
+ const showEvent = EventHandler.trigger(this._element, EVENT_SHOW);
+ if (showEvent.defaultPrevented) {
+ return;
+ }
+ this._clearTimeout();
+ if (this._config.animation) {
+ this._element.classList.add(CLASS_NAME_FADE);
+ }
+ const complete = () => {
+ this._element.classList.remove(CLASS_NAME_SHOWING);
+ EventHandler.trigger(this._element, EVENT_SHOWN);
+ this._maybeScheduleHide();
+ };
+ this._element.classList.remove(CLASS_NAME_HIDE); // @deprecated
+ reflow(this._element);
+ this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING);
+ this._queueCallback(complete, this._element, this._config.animation);
+ }
+ hide() {
+ if (!this.isShown()) {
+ return;
+ }
+ const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE);
+ if (hideEvent.defaultPrevented) {
+ return;
+ }
+ const complete = () => {
+ this._element.classList.add(CLASS_NAME_HIDE); // @deprecated
+ this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW);
+ EventHandler.trigger(this._element, EVENT_HIDDEN);
+ };
+ this._element.classList.add(CLASS_NAME_SHOWING);
+ this._queueCallback(complete, this._element, this._config.animation);
+ }
+ dispose() {
+ this._clearTimeout();
+ if (this.isShown()) {
+ this._element.classList.remove(CLASS_NAME_SHOW);
+ }
+ super.dispose();
+ }
+ isShown() {
+ return this._element.classList.contains(CLASS_NAME_SHOW);
+ }
+
+ // Private
+
+ _maybeScheduleHide() {
+ if (!this._config.autohide) {
+ return;
+ }
+ if (this._hasMouseInteraction || this._hasKeyboardInteraction) {
+ return;
+ }
+ this._timeout = setTimeout(() => {
+ this.hide();
+ }, this._config.delay);
+ }
+ _onInteraction(event, isInteracting) {
+ switch (event.type) {
+ case 'mouseover':
+ case 'mouseout':
+ {
+ this._hasMouseInteraction = isInteracting;
+ break;
+ }
+ case 'focusin':
+ case 'focusout':
+ {
+ this._hasKeyboardInteraction = isInteracting;
+ break;
+ }
+ }
+ if (isInteracting) {
+ this._clearTimeout();
+ return;
+ }
+ const nextElement = event.relatedTarget;
+ if (this._element === nextElement || this._element.contains(nextElement)) {
+ return;
+ }
+ this._maybeScheduleHide();
+ }
+ _setListeners() {
+ EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true));
+ EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false));
+ EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true));
+ EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false));
+ }
+ _clearTimeout() {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+
+ // Static
+ static jQueryInterface(config) {
+ return this.each(function () {
+ const data = Toast.getOrCreateInstance(this, config);
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError(`No method named "${config}"`);
+ }
+ data[config](this);
+ }
+ });
+ }
+ }
+
+ /**
+ * Data API implementation
+ */
+
+ enableDismissTrigger(Toast);
+
+ /**
+ * jQuery
+ */
+
+ defineJQueryPlugin(Toast);
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap index.umd.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+ const index_umd = {
+ Alert,
+ Button,
+ Carousel,
+ Collapse,
+ Dropdown,
+ Modal,
+ Offcanvas,
+ Popover,
+ ScrollSpy,
+ Tab,
+ Toast,
+ Tooltip
+ };
+
+ return index_umd;
+
+}));
diff --git a/src/static/scripts/bootstrap.css b/src/static/scripts/bootstrap.css
index 614c226f..11e83fa5 100644
--- a/src/static/scripts/bootstrap.css
+++ b/src/static/scripts/bootstrap.css
@@ -1,11 +1,11 @@
@charset "UTF-8";
/*!
- * Bootstrap v5.2.3 (https://getbootstrap.com/)
- * Copyright 2011-2022 The Bootstrap Authors
- * Copyright 2011-2022 Twitter, Inc.
+ * Bootstrap v5.3.1 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
-:root {
+:root,
+[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
@@ -45,10 +45,32 @@
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
+ --bs-primary-text-emphasis: #052c65;
+ --bs-secondary-text-emphasis: #2b2f32;
+ --bs-success-text-emphasis: #0a3622;
+ --bs-info-text-emphasis: #055160;
+ --bs-warning-text-emphasis: #664d03;
+ --bs-danger-text-emphasis: #58151c;
+ --bs-light-text-emphasis: #495057;
+ --bs-dark-text-emphasis: #495057;
+ --bs-primary-bg-subtle: #cfe2ff;
+ --bs-secondary-bg-subtle: #e2e3e5;
+ --bs-success-bg-subtle: #d1e7dd;
+ --bs-info-bg-subtle: #cff4fc;
+ --bs-warning-bg-subtle: #fff3cd;
+ --bs-danger-bg-subtle: #f8d7da;
+ --bs-light-bg-subtle: #fcfcfd;
+ --bs-dark-bg-subtle: #ced4da;
+ --bs-primary-border-subtle: #9ec5fe;
+ --bs-secondary-border-subtle: #c4c8cb;
+ --bs-success-border-subtle: #a3cfbb;
+ --bs-info-border-subtle: #9eeaf9;
+ --bs-warning-border-subtle: #ffe69c;
+ --bs-danger-border-subtle: #f1aeb5;
+ --bs-light-border-subtle: #e9ecef;
+ --bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
- --bs-body-color-rgb: 33, 37, 41;
- --bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
@@ -57,7 +79,27 @@
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
+ --bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #fff;
+ --bs-body-bg-rgb: 255, 255, 255;
+ --bs-emphasis-color: #000;
+ --bs-emphasis-color-rgb: 0, 0, 0;
+ --bs-secondary-color: rgba(33, 37, 41, 0.75);
+ --bs-secondary-color-rgb: 33, 37, 41;
+ --bs-secondary-bg: #e9ecef;
+ --bs-secondary-bg-rgb: 233, 236, 239;
+ --bs-tertiary-color: rgba(33, 37, 41, 0.5);
+ --bs-tertiary-color-rgb: 33, 37, 41;
+ --bs-tertiary-bg: #f8f9fa;
+ --bs-tertiary-bg-rgb: 248, 249, 250;
+ --bs-heading-color: inherit;
+ --bs-link-color: #0d6efd;
+ --bs-link-color-rgb: 13, 110, 253;
+ --bs-link-decoration: underline;
+ --bs-link-hover-color: #0a58ca;
+ --bs-link-hover-color-rgb: 10, 88, 202;
+ --bs-code-color: #d63384;
+ --bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
@@ -66,12 +108,74 @@
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
- --bs-border-radius-2xl: 2rem;
+ --bs-border-radius-xxl: 2rem;
+ --bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
- --bs-link-color: #0d6efd;
- --bs-link-hover-color: #0a58ca;
- --bs-code-color: #d63384;
- --bs-highlight-bg: #fff3cd;
+ --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+ --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
+ --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
+ --bs-focus-ring-width: 0.25rem;
+ --bs-focus-ring-opacity: 0.25;
+ --bs-focus-ring-color: rgba(13, 110, 253, 0.25);
+ --bs-form-valid-color: #198754;
+ --bs-form-valid-border-color: #198754;
+ --bs-form-invalid-color: #dc3545;
+ --bs-form-invalid-border-color: #dc3545;
+}
+
+[data-bs-theme=dark] {
+ color-scheme: dark;
+ --bs-body-color: #dee2e6;
+ --bs-body-color-rgb: 222, 226, 230;
+ --bs-body-bg: #212529;
+ --bs-body-bg-rgb: 33, 37, 41;
+ --bs-emphasis-color: #fff;
+ --bs-emphasis-color-rgb: 255, 255, 255;
+ --bs-secondary-color: rgba(222, 226, 230, 0.75);
+ --bs-secondary-color-rgb: 222, 226, 230;
+ --bs-secondary-bg: #343a40;
+ --bs-secondary-bg-rgb: 52, 58, 64;
+ --bs-tertiary-color: rgba(222, 226, 230, 0.5);
+ --bs-tertiary-color-rgb: 222, 226, 230;
+ --bs-tertiary-bg: #2b3035;
+ --bs-tertiary-bg-rgb: 43, 48, 53;
+ --bs-primary-text-emphasis: #6ea8fe;
+ --bs-secondary-text-emphasis: #a7acb1;
+ --bs-success-text-emphasis: #75b798;
+ --bs-info-text-emphasis: #6edff6;
+ --bs-warning-text-emphasis: #ffda6a;
+ --bs-danger-text-emphasis: #ea868f;
+ --bs-light-text-emphasis: #f8f9fa;
+ --bs-dark-text-emphasis: #dee2e6;
+ --bs-primary-bg-subtle: #031633;
+ --bs-secondary-bg-subtle: #161719;
+ --bs-success-bg-subtle: #051b11;
+ --bs-info-bg-subtle: #032830;
+ --bs-warning-bg-subtle: #332701;
+ --bs-danger-bg-subtle: #2c0b0e;
+ --bs-light-bg-subtle: #343a40;
+ --bs-dark-bg-subtle: #1a1d20;
+ --bs-primary-border-subtle: #084298;
+ --bs-secondary-border-subtle: #41464b;
+ --bs-success-border-subtle: #0f5132;
+ --bs-info-border-subtle: #087990;
+ --bs-warning-border-subtle: #997404;
+ --bs-danger-border-subtle: #842029;
+ --bs-light-border-subtle: #495057;
+ --bs-dark-border-subtle: #343a40;
+ --bs-heading-color: inherit;
+ --bs-link-color: #6ea8fe;
+ --bs-link-hover-color: #8bb9fe;
+ --bs-link-color-rgb: 110, 168, 254;
+ --bs-link-hover-color-rgb: 139, 185, 254;
+ --bs-code-color: #e685b5;
+ --bs-border-color: #495057;
+ --bs-border-color-translucent: rgba(255, 255, 255, 0.15);
+ --bs-form-valid-color: #75b798;
+ --bs-form-valid-border-color: #75b798;
+ --bs-form-invalid-color: #ea868f;
+ --bs-form-invalid-border-color: #ea868f;
}
*,
@@ -103,7 +207,7 @@ hr {
margin: 1rem 0;
color: inherit;
border: 0;
- border-top: 1px solid;
+ border-top: var(--bs-border-width) solid;
opacity: 0.25;
}
@@ -112,6 +216,7 @@ h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 {
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
+ color: var(--bs-heading-color);
}
h1, .h1 {
@@ -240,11 +345,11 @@ sup {
}
a {
- color: var(--bs-link-color);
+ color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
text-decoration: underline;
}
a:hover {
- color: var(--bs-link-hover-color);
+ --bs-link-color-rgb: var(--bs-link-hover-color-rgb);
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
@@ -311,7 +416,7 @@ table {
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
- color: #6c757d;
+ color: var(--bs-secondary-color);
text-align: left;
}
@@ -435,8 +540,8 @@ legend + * {
}
[type=search] {
- outline-offset: -2px;
-webkit-appearance: textfield;
+ outline-offset: -2px;
}
/* rtl:raw:
@@ -604,9 +709,9 @@ progress {
.img-thumbnail {
padding: 0.25rem;
- background-color: #fff;
- border: 1px solid var(--bs-border-color);
- border-radius: 0.375rem;
+ background-color: var(--bs-body-bg);
+ border: var(--bs-border-width) solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
max-width: 100%;
height: auto;
}
@@ -622,7 +727,7 @@ progress {
.figure-caption {
font-size: 0.875em;
- color: #6c757d;
+ color: var(--bs-secondary-color);
}
.container,
@@ -666,6 +771,15 @@ progress {
max-width: 1320px;
}
}
+:root {
+ --bs-breakpoint-xs: 0;
+ --bs-breakpoint-sm: 576px;
+ --bs-breakpoint-md: 768px;
+ --bs-breakpoint-lg: 992px;
+ --bs-breakpoint-xl: 1200px;
+ --bs-breakpoint-xxl: 1400px;
+}
+
.row {
--bs-gutter-x: 1.5rem;
--bs-gutter-y: 0;
@@ -1013,51 +1127,51 @@ progress {
margin-left: 91.66666667%;
}
.g-sm-0,
-.gx-sm-0 {
+ .gx-sm-0 {
--bs-gutter-x: 0;
}
.g-sm-0,
-.gy-sm-0 {
+ .gy-sm-0 {
--bs-gutter-y: 0;
}
.g-sm-1,
-.gx-sm-1 {
+ .gx-sm-1 {
--bs-gutter-x: 0.25rem;
}
.g-sm-1,
-.gy-sm-1 {
+ .gy-sm-1 {
--bs-gutter-y: 0.25rem;
}
.g-sm-2,
-.gx-sm-2 {
+ .gx-sm-2 {
--bs-gutter-x: 0.5rem;
}
.g-sm-2,
-.gy-sm-2 {
+ .gy-sm-2 {
--bs-gutter-y: 0.5rem;
}
.g-sm-3,
-.gx-sm-3 {
+ .gx-sm-3 {
--bs-gutter-x: 1rem;
}
.g-sm-3,
-.gy-sm-3 {
+ .gy-sm-3 {
--bs-gutter-y: 1rem;
}
.g-sm-4,
-.gx-sm-4 {
+ .gx-sm-4 {
--bs-gutter-x: 1.5rem;
}
.g-sm-4,
-.gy-sm-4 {
+ .gy-sm-4 {
--bs-gutter-y: 1.5rem;
}
.g-sm-5,
-.gx-sm-5 {
+ .gx-sm-5 {
--bs-gutter-x: 3rem;
}
.g-sm-5,
-.gy-sm-5 {
+ .gy-sm-5 {
--bs-gutter-y: 3rem;
}
}
@@ -1182,51 +1296,51 @@ progress {
margin-left: 91.66666667%;
}
.g-md-0,
-.gx-md-0 {
+ .gx-md-0 {
--bs-gutter-x: 0;
}
.g-md-0,
-.gy-md-0 {
+ .gy-md-0 {
--bs-gutter-y: 0;
}
.g-md-1,
-.gx-md-1 {
+ .gx-md-1 {
--bs-gutter-x: 0.25rem;
}
.g-md-1,
-.gy-md-1 {
+ .gy-md-1 {
--bs-gutter-y: 0.25rem;
}
.g-md-2,
-.gx-md-2 {
+ .gx-md-2 {
--bs-gutter-x: 0.5rem;
}
.g-md-2,
-.gy-md-2 {
+ .gy-md-2 {
--bs-gutter-y: 0.5rem;
}
.g-md-3,
-.gx-md-3 {
+ .gx-md-3 {
--bs-gutter-x: 1rem;
}
.g-md-3,
-.gy-md-3 {
+ .gy-md-3 {
--bs-gutter-y: 1rem;
}
.g-md-4,
-.gx-md-4 {
+ .gx-md-4 {
--bs-gutter-x: 1.5rem;
}
.g-md-4,
-.gy-md-4 {
+ .gy-md-4 {
--bs-gutter-y: 1.5rem;
}
.g-md-5,
-.gx-md-5 {
+ .gx-md-5 {
--bs-gutter-x: 3rem;
}
.g-md-5,
-.gy-md-5 {
+ .gy-md-5 {
--bs-gutter-y: 3rem;
}
}
@@ -1351,51 +1465,51 @@ progress {
margin-left: 91.66666667%;
}
.g-lg-0,
-.gx-lg-0 {
+ .gx-lg-0 {
--bs-gutter-x: 0;
}
.g-lg-0,
-.gy-lg-0 {
+ .gy-lg-0 {
--bs-gutter-y: 0;
}
.g-lg-1,
-.gx-lg-1 {
+ .gx-lg-1 {
--bs-gutter-x: 0.25rem;
}
.g-lg-1,
-.gy-lg-1 {
+ .gy-lg-1 {
--bs-gutter-y: 0.25rem;
}
.g-lg-2,
-.gx-lg-2 {
+ .gx-lg-2 {
--bs-gutter-x: 0.5rem;
}
.g-lg-2,
-.gy-lg-2 {
+ .gy-lg-2 {
--bs-gutter-y: 0.5rem;
}
.g-lg-3,
-.gx-lg-3 {
+ .gx-lg-3 {
--bs-gutter-x: 1rem;
}
.g-lg-3,
-.gy-lg-3 {
+ .gy-lg-3 {
--bs-gutter-y: 1rem;
}
.g-lg-4,
-.gx-lg-4 {
+ .gx-lg-4 {
--bs-gutter-x: 1.5rem;
}
.g-lg-4,
-.gy-lg-4 {
+ .gy-lg-4 {
--bs-gutter-y: 1.5rem;
}
.g-lg-5,
-.gx-lg-5 {
+ .gx-lg-5 {
--bs-gutter-x: 3rem;
}
.g-lg-5,
-.gy-lg-5 {
+ .gy-lg-5 {
--bs-gutter-y: 3rem;
}
}
@@ -1520,51 +1634,51 @@ progress {
margin-left: 91.66666667%;
}
.g-xl-0,
-.gx-xl-0 {
+ .gx-xl-0 {
--bs-gutter-x: 0;
}
.g-xl-0,
-.gy-xl-0 {
+ .gy-xl-0 {
--bs-gutter-y: 0;
}
.g-xl-1,
-.gx-xl-1 {
+ .gx-xl-1 {
--bs-gutter-x: 0.25rem;
}
.g-xl-1,
-.gy-xl-1 {
+ .gy-xl-1 {
--bs-gutter-y: 0.25rem;
}
.g-xl-2,
-.gx-xl-2 {
+ .gx-xl-2 {
--bs-gutter-x: 0.5rem;
}
.g-xl-2,
-.gy-xl-2 {
+ .gy-xl-2 {
--bs-gutter-y: 0.5rem;
}
.g-xl-3,
-.gx-xl-3 {
+ .gx-xl-3 {
--bs-gutter-x: 1rem;
}
.g-xl-3,
-.gy-xl-3 {
+ .gy-xl-3 {
--bs-gutter-y: 1rem;
}
.g-xl-4,
-.gx-xl-4 {
+ .gx-xl-4 {
--bs-gutter-x: 1.5rem;
}
.g-xl-4,
-.gy-xl-4 {
+ .gy-xl-4 {
--bs-gutter-y: 1.5rem;
}
.g-xl-5,
-.gx-xl-5 {
+ .gx-xl-5 {
--bs-gutter-x: 3rem;
}
.g-xl-5,
-.gy-xl-5 {
+ .gy-xl-5 {
--bs-gutter-y: 3rem;
}
}
@@ -1689,57 +1803,61 @@ progress {
margin-left: 91.66666667%;
}
.g-xxl-0,
-.gx-xxl-0 {
+ .gx-xxl-0 {
--bs-gutter-x: 0;
}
.g-xxl-0,
-.gy-xxl-0 {
+ .gy-xxl-0 {
--bs-gutter-y: 0;
}
.g-xxl-1,
-.gx-xxl-1 {
+ .gx-xxl-1 {
--bs-gutter-x: 0.25rem;
}
.g-xxl-1,
-.gy-xxl-1 {
+ .gy-xxl-1 {
--bs-gutter-y: 0.25rem;
}
.g-xxl-2,
-.gx-xxl-2 {
+ .gx-xxl-2 {
--bs-gutter-x: 0.5rem;
}
.g-xxl-2,
-.gy-xxl-2 {
+ .gy-xxl-2 {
--bs-gutter-y: 0.5rem;
}
.g-xxl-3,
-.gx-xxl-3 {
+ .gx-xxl-3 {
--bs-gutter-x: 1rem;
}
.g-xxl-3,
-.gy-xxl-3 {
+ .gy-xxl-3 {
--bs-gutter-y: 1rem;
}
.g-xxl-4,
-.gx-xxl-4 {
+ .gx-xxl-4 {
--bs-gutter-x: 1.5rem;
}
.g-xxl-4,
-.gy-xxl-4 {
+ .gy-xxl-4 {
--bs-gutter-y: 1.5rem;
}
.g-xxl-5,
-.gx-xxl-5 {
+ .gx-xxl-5 {
--bs-gutter-x: 3rem;
}
.g-xxl-5,
-.gy-xxl-5 {
+ .gy-xxl-5 {
--bs-gutter-y: 3rem;
}
}
.table {
+ --bs-table-color-type: initial;
+ --bs-table-bg-type: initial;
+ --bs-table-color-state: initial;
+ --bs-table-bg-state: initial;
--bs-table-color: var(--bs-body-color);
- --bs-table-bg: transparent;
+ --bs-table-bg: var(--bs-body-bg);
--bs-table-border-color: var(--bs-border-color);
--bs-table-accent-bg: transparent;
--bs-table-striped-color: var(--bs-body-color);
@@ -1750,15 +1868,15 @@ progress {
--bs-table-hover-bg: rgba(0, 0, 0, 0.075);
width: 100%;
margin-bottom: 1rem;
- color: var(--bs-table-color);
vertical-align: top;
border-color: var(--bs-table-border-color);
}
.table > :not(caption) > * > * {
padding: 0.5rem 0.5rem;
+ color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));
background-color: var(--bs-table-bg);
- border-bottom-width: 1px;
- box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg);
+ border-bottom-width: var(--bs-border-width);
+ box-shadow: inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)));
}
.table > tbody {
vertical-align: inherit;
@@ -1768,7 +1886,7 @@ progress {
}
.table-group-divider {
- border-top: 2px solid currentcolor;
+ border-top: calc(var(--bs-border-width) * 2) solid currentcolor;
}
.caption-top {
@@ -1780,10 +1898,10 @@ progress {
}
.table-bordered > :not(caption) > * {
- border-width: 1px 0;
+ border-width: var(--bs-border-width) 0;
}
.table-bordered > :not(caption) > * > * {
- border-width: 0 1px;
+ border-width: 0 var(--bs-border-width);
}
.table-borderless > :not(caption) > * > * {
@@ -1794,23 +1912,23 @@ progress {
}
.table-striped > tbody > tr:nth-of-type(odd) > * {
- --bs-table-accent-bg: var(--bs-table-striped-bg);
- color: var(--bs-table-striped-color);
+ --bs-table-color-type: var(--bs-table-striped-color);
+ --bs-table-bg-type: var(--bs-table-striped-bg);
}
.table-striped-columns > :not(caption) > tr > :nth-child(even) {
- --bs-table-accent-bg: var(--bs-table-striped-bg);
- color: var(--bs-table-striped-color);
+ --bs-table-color-type: var(--bs-table-striped-color);
+ --bs-table-bg-type: var(--bs-table-striped-bg);
}
.table-active {
- --bs-table-accent-bg: var(--bs-table-active-bg);
- color: var(--bs-table-active-color);
+ --bs-table-color-state: var(--bs-table-active-color);
+ --bs-table-bg-state: var(--bs-table-active-bg);
}
.table-hover > tbody > tr:hover > * {
- --bs-table-accent-bg: var(--bs-table-hover-bg);
- color: var(--bs-table-hover-color);
+ --bs-table-color-state: var(--bs-table-hover-color);
+ --bs-table-bg-state: var(--bs-table-hover-bg);
}
.table-primary {
@@ -1965,29 +2083,29 @@ progress {
}
.col-form-label {
- padding-top: calc(0.375rem + 1px);
- padding-bottom: calc(0.375rem + 1px);
+ padding-top: calc(0.375rem + var(--bs-border-width));
+ padding-bottom: calc(0.375rem + var(--bs-border-width));
margin-bottom: 0;
font-size: inherit;
line-height: 1.5;
}
.col-form-label-lg {
- padding-top: calc(0.5rem + 1px);
- padding-bottom: calc(0.5rem + 1px);
+ padding-top: calc(0.5rem + var(--bs-border-width));
+ padding-bottom: calc(0.5rem + var(--bs-border-width));
font-size: 1.25rem;
}
.col-form-label-sm {
- padding-top: calc(0.25rem + 1px);
- padding-bottom: calc(0.25rem + 1px);
+ padding-top: calc(0.25rem + var(--bs-border-width));
+ padding-bottom: calc(0.25rem + var(--bs-border-width));
font-size: 0.875rem;
}
.form-text {
margin-top: 0.25rem;
font-size: 0.875em;
- color: #6c757d;
+ color: var(--bs-secondary-color);
}
.form-control {
@@ -1997,14 +2115,14 @@ progress {
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
- color: #212529;
- background-color: #fff;
- background-clip: padding-box;
- border: 1px solid #ced4da;
+ color: var(--bs-body-color);
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
- border-radius: 0.375rem;
+ background-color: var(--bs-body-bg);
+ background-clip: padding-box;
+ border: var(--bs-border-width) solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
@@ -2019,25 +2137,31 @@ progress {
cursor: pointer;
}
.form-control:focus {
- color: #212529;
- background-color: #fff;
+ color: var(--bs-body-color);
+ background-color: var(--bs-body-bg);
border-color: #86b7fe;
outline: 0;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}
.form-control::-webkit-date-and-time-value {
+ min-width: 85px;
height: 1.5em;
+ margin: 0;
+}
+.form-control::-webkit-datetime-edit {
+ display: block;
+ padding: 0;
}
.form-control::-moz-placeholder {
- color: #6c757d;
+ color: var(--bs-secondary-color);
opacity: 1;
}
.form-control::placeholder {
- color: #6c757d;
+ color: var(--bs-secondary-color);
opacity: 1;
}
.form-control:disabled {
- background-color: #e9ecef;
+ background-color: var(--bs-secondary-bg);
opacity: 1;
}
.form-control::-webkit-file-upload-button {
@@ -2045,13 +2169,13 @@ progress {
margin: -0.375rem -0.75rem;
-webkit-margin-end: 0.75rem;
margin-inline-end: 0.75rem;
- color: #212529;
- background-color: #e9ecef;
+ color: var(--bs-body-color);
+ background-color: var(--bs-tertiary-bg);
pointer-events: none;
border-color: inherit;
border-style: solid;
border-width: 0;
- border-inline-end-width: 1px;
+ border-inline-end-width: var(--bs-border-width);
border-radius: 0;
-webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
@@ -2061,13 +2185,13 @@ progress {
margin: -0.375rem -0.75rem;
-webkit-margin-end: 0.75rem;
margin-inline-end: 0.75rem;
- color: #212529;
- background-color: #e9ecef;
+ color: var(--bs-body-color);
+ background-color: var(--bs-tertiary-bg);
pointer-events: none;
border-color: inherit;
border-style: solid;
border-width: 0;
- border-inline-end-width: 1px;
+ border-inline-end-width: var(--bs-border-width);
border-radius: 0;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
@@ -2081,10 +2205,10 @@ progress {
}
}
.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {
- background-color: #dde0e3;
+ background-color: var(--bs-secondary-bg);
}
.form-control:hover:not(:disabled):not([readonly])::file-selector-button {
- background-color: #dde0e3;
+ background-color: var(--bs-secondary-bg);
}
.form-control-plaintext {
@@ -2093,10 +2217,10 @@ progress {
padding: 0.375rem 0;
margin-bottom: 0;
line-height: 1.5;
- color: #212529;
+ color: var(--bs-body-color);
background-color: transparent;
border: solid transparent;
- border-width: 1px 0;
+ border-width: var(--bs-border-width) 0;
}
.form-control-plaintext:focus {
outline: 0;
@@ -2107,10 +2231,10 @@ progress {
}
.form-control-sm {
- min-height: calc(1.5em + 0.5rem + 2px);
+ min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
- border-radius: 0.25rem;
+ border-radius: var(--bs-border-radius-sm);
}
.form-control-sm::-webkit-file-upload-button {
padding: 0.25rem 0.5rem;
@@ -2126,10 +2250,10 @@ progress {
}
.form-control-lg {
- min-height: calc(1.5em + 1rem + 2px);
+ min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));
padding: 0.5rem 1rem;
font-size: 1.25rem;
- border-radius: 0.5rem;
+ border-radius: var(--bs-border-radius-lg);
}
.form-control-lg::-webkit-file-upload-button {
padding: 0.5rem 1rem;
@@ -2145,18 +2269,18 @@ progress {
}
textarea.form-control {
- min-height: calc(1.5em + 0.75rem + 2px);
+ min-height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));
}
textarea.form-control-sm {
- min-height: calc(1.5em + 0.5rem + 2px);
+ min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));
}
textarea.form-control-lg {
- min-height: calc(1.5em + 1rem + 2px);
+ min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));
}
.form-control-color {
width: 3rem;
- height: calc(1.5em + 0.75rem + 2px);
+ height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));
padding: 0.375rem;
}
.form-control-color:not(:disabled):not([readonly]) {
@@ -2164,38 +2288,39 @@ textarea.form-control-lg {
}
.form-control-color::-moz-color-swatch {
border: 0 !important;
- border-radius: 0.375rem;
+ border-radius: var(--bs-border-radius);
}
.form-control-color::-webkit-color-swatch {
- border-radius: 0.375rem;
+ border: 0 !important;
+ border-radius: var(--bs-border-radius);
}
.form-control-color.form-control-sm {
- height: calc(1.5em + 0.5rem + 2px);
+ height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));
}
.form-control-color.form-control-lg {
- height: calc(1.5em + 1rem + 2px);
+ height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));
}
.form-select {
+ --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
display: block;
width: 100%;
padding: 0.375rem 2.25rem 0.375rem 0.75rem;
- -moz-padding-start: calc(0.75rem - 3px);
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
- color: #212529;
- background-color: #fff;
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
+ color: var(--bs-body-color);
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background-color: var(--bs-body-bg);
+ background-image: var(--bs-form-select-bg-img), var(--bs-form-select-bg-icon, none);
background-repeat: no-repeat;
background-position: right 0.75rem center;
background-size: 16px 12px;
- border: 1px solid #ced4da;
- border-radius: 0.375rem;
+ border: var(--bs-border-width) solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
}
@media (prefers-reduced-motion: reduce) {
.form-select {
@@ -2212,11 +2337,11 @@ textarea.form-control-lg {
background-image: none;
}
.form-select:disabled {
- background-color: #e9ecef;
+ background-color: var(--bs-secondary-bg);
}
.form-select:-moz-focusring {
color: transparent;
- text-shadow: 0 0 0 #212529;
+ text-shadow: 0 0 0 var(--bs-body-color);
}
.form-select-sm {
@@ -2224,7 +2349,7 @@ textarea.form-control-lg {
padding-bottom: 0.25rem;
padding-left: 0.5rem;
font-size: 0.875rem;
- border-radius: 0.25rem;
+ border-radius: var(--bs-border-radius-sm);
}
.form-select-lg {
@@ -2232,7 +2357,11 @@ textarea.form-control-lg {
padding-bottom: 0.5rem;
padding-left: 1rem;
font-size: 1.25rem;
- border-radius: 0.5rem;
+ border-radius: var(--bs-border-radius-lg);
+}
+
+[data-bs-theme=dark] .form-select {
+ --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
}
.form-check {
@@ -2258,18 +2387,20 @@ textarea.form-control-lg {
}
.form-check-input {
+ --bs-form-check-bg: var(--bs-body-bg);
width: 1em;
height: 1em;
margin-top: 0.25em;
vertical-align: top;
- background-color: #fff;
- background-repeat: no-repeat;
- background-position: center;
- background-size: contain;
- border: 1px solid rgba(0, 0, 0, 0.25);
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
+ background-color: var(--bs-form-check-bg);
+ background-image: var(--bs-form-check-bg-image);
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: contain;
+ border: var(--bs-border-width) solid var(--bs-border-color);
-webkit-print-color-adjust: exact;
color-adjust: exact;
print-color-adjust: exact;
@@ -2293,15 +2424,15 @@ textarea.form-control-lg {
border-color: #0d6efd;
}
.form-check-input:checked[type=checkbox] {
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");
+ --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");
}
.form-check-input:checked[type=radio] {
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e");
+ --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e");
}
.form-check-input[type=checkbox]:indeterminate {
background-color: #0d6efd;
border-color: #0d6efd;
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e");
+ --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e");
}
.form-check-input:disabled {
pointer-events: none;
@@ -2317,9 +2448,10 @@ textarea.form-control-lg {
padding-left: 2.5em;
}
.form-switch .form-check-input {
+ --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
width: 2em;
margin-left: -2.5em;
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
+ background-image: var(--bs-form-switch-bg);
background-position: left center;
border-radius: 2em;
transition: background-position 0.15s ease-in-out;
@@ -2330,11 +2462,11 @@ textarea.form-control-lg {
}
}
.form-switch .form-check-input:focus {
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e");
+ --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e");
}
.form-switch .form-check-input:checked {
background-position: right center;
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
+ --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
}
.form-switch.form-check-reverse {
padding-right: 2.5em;
@@ -2361,14 +2493,18 @@ textarea.form-control-lg {
opacity: 0.65;
}
+[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus) {
+ --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e");
+}
+
.form-range {
width: 100%;
height: 1.5rem;
padding: 0;
- background-color: transparent;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
+ background-color: transparent;
}
.form-range:focus {
outline: 0;
@@ -2386,13 +2522,13 @@ textarea.form-control-lg {
width: 1rem;
height: 1rem;
margin-top: -0.25rem;
+ -webkit-appearance: none;
+ appearance: none;
background-color: #0d6efd;
border: 0;
border-radius: 1rem;
-webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
- -webkit-appearance: none;
- appearance: none;
}
@media (prefers-reduced-motion: reduce) {
.form-range::-webkit-slider-thumb {
@@ -2408,20 +2544,20 @@ textarea.form-control-lg {
height: 0.5rem;
color: transparent;
cursor: pointer;
- background-color: #dee2e6;
+ background-color: var(--bs-tertiary-bg);
border-color: transparent;
border-radius: 1rem;
}
.form-range::-moz-range-thumb {
width: 1rem;
height: 1rem;
+ -moz-appearance: none;
+ appearance: none;
background-color: #0d6efd;
border: 0;
border-radius: 1rem;
-moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
- -moz-appearance: none;
- appearance: none;
}
@media (prefers-reduced-motion: reduce) {
.form-range::-moz-range-thumb {
@@ -2437,7 +2573,7 @@ textarea.form-control-lg {
height: 0.5rem;
color: transparent;
cursor: pointer;
- background-color: #dee2e6;
+ background-color: var(--bs-tertiary-bg);
border-color: transparent;
border-radius: 1rem;
}
@@ -2445,10 +2581,10 @@ textarea.form-control-lg {
pointer-events: none;
}
.form-range:disabled::-webkit-slider-thumb {
- background-color: #adb5bd;
+ background-color: var(--bs-secondary-color);
}
.form-range:disabled::-moz-range-thumb {
- background-color: #adb5bd;
+ background-color: var(--bs-secondary-color);
}
.form-floating {
@@ -2457,14 +2593,15 @@ textarea.form-control-lg {
.form-floating > .form-control,
.form-floating > .form-control-plaintext,
.form-floating > .form-select {
- height: calc(3.5rem + 2px);
+ height: calc(3.5rem + calc(var(--bs-border-width) * 2));
+ min-height: calc(3.5rem + calc(var(--bs-border-width) * 2));
line-height: 1.25;
}
.form-floating > label {
position: absolute;
top: 0;
left: 0;
- width: 100%;
+ z-index: 2;
height: 100%;
padding: 1rem 0.75rem;
overflow: hidden;
@@ -2472,7 +2609,7 @@ textarea.form-control-lg {
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
- border: 1px solid transparent;
+ border: var(--bs-border-width) solid transparent;
transform-origin: 0 0;
transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;
}
@@ -2512,22 +2649,51 @@ textarea.form-control-lg {
padding-bottom: 0.625rem;
}
.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label {
- opacity: 0.65;
+ color: rgba(var(--bs-body-color-rgb), 0.65);
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
}
.form-floating > .form-control:focus ~ label,
.form-floating > .form-control:not(:placeholder-shown) ~ label,
.form-floating > .form-control-plaintext ~ label,
.form-floating > .form-select ~ label {
- opacity: 0.65;
+ color: rgba(var(--bs-body-color-rgb), 0.65);
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
}
+.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label::after {
+ position: absolute;
+ inset: 1rem 0.375rem;
+ z-index: -1;
+ height: 1.5em;
+ content: "";
+ background-color: var(--bs-body-bg);
+ border-radius: var(--bs-border-radius);
+}
+.form-floating > .form-control:focus ~ label::after,
+.form-floating > .form-control:not(:placeholder-shown) ~ label::after,
+.form-floating > .form-control-plaintext ~ label::after,
+.form-floating > .form-select ~ label::after {
+ position: absolute;
+ inset: 1rem 0.375rem;
+ z-index: -1;
+ height: 1.5em;
+ content: "";
+ background-color: var(--bs-body-bg);
+ border-radius: var(--bs-border-radius);
+}
.form-floating > .form-control:-webkit-autofill ~ label {
- opacity: 0.65;
+ color: rgba(var(--bs-body-color-rgb), 0.65);
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
}
.form-floating > .form-control-plaintext ~ label {
- border-width: 1px 0;
+ border-width: var(--bs-border-width) 0;
+}
+.form-floating > :disabled ~ label,
+.form-floating > .form-control:disabled ~ label {
+ color: #6c757d;
+}
+.form-floating > :disabled ~ label::after,
+.form-floating > .form-control:disabled ~ label::after {
+ background-color: var(--bs-secondary-bg);
}
.input-group {
@@ -2565,12 +2731,12 @@ textarea.form-control-lg {
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
- color: #212529;
+ color: var(--bs-body-color);
text-align: center;
white-space: nowrap;
- background-color: #e9ecef;
- border: 1px solid #ced4da;
- border-radius: 0.375rem;
+ background-color: var(--bs-tertiary-bg);
+ border: var(--bs-border-width) solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
}
.input-group-lg > .form-control,
@@ -2579,7 +2745,7 @@ textarea.form-control-lg {
.input-group-lg > .btn {
padding: 0.5rem 1rem;
font-size: 1.25rem;
- border-radius: 0.5rem;
+ border-radius: var(--bs-border-radius-lg);
}
.input-group-sm > .form-control,
@@ -2588,7 +2754,7 @@ textarea.form-control-lg {
.input-group-sm > .btn {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
- border-radius: 0.25rem;
+ border-radius: var(--bs-border-radius-sm);
}
.input-group-lg > .form-select,
@@ -2611,7 +2777,7 @@ textarea.form-control-lg {
border-bottom-right-radius: 0;
}
.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
- margin-left: -1px;
+ margin-left: calc(var(--bs-border-width) * -1);
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@@ -2626,7 +2792,7 @@ textarea.form-control-lg {
width: 100%;
margin-top: 0.25rem;
font-size: 0.875em;
- color: #198754;
+ color: var(--bs-form-valid-color);
}
.valid-tooltip {
@@ -2639,8 +2805,8 @@ textarea.form-control-lg {
margin-top: 0.1rem;
font-size: 0.875rem;
color: #fff;
- background-color: rgba(25, 135, 84, 0.9);
- border-radius: 0.375rem;
+ background-color: var(--bs-success);
+ border-radius: var(--bs-border-radius);
}
.was-validated :valid ~ .valid-feedback,
@@ -2651,7 +2817,7 @@ textarea.form-control-lg {
}
.was-validated .form-control:valid, .form-control.is-valid {
- border-color: #198754;
+ border-color: var(--bs-form-valid-border-color);
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
@@ -2659,8 +2825,8 @@ textarea.form-control-lg {
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.was-validated .form-control:valid:focus, .form-control.is-valid:focus {
- border-color: #198754;
- box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
+ border-color: var(--bs-form-valid-border-color);
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);
}
.was-validated textarea.form-control:valid, textarea.form-control.is-valid {
@@ -2669,17 +2835,17 @@ textarea.form-control-lg {
}
.was-validated .form-select:valid, .form-select.is-valid {
- border-color: #198754;
+ border-color: var(--bs-form-valid-border-color);
}
.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"] {
+ --bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
padding-right: 4.125rem;
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
background-position: right 0.75rem center, center right 2.25rem;
background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.was-validated .form-select:valid:focus, .form-select.is-valid:focus {
- border-color: #198754;
- box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
+ border-color: var(--bs-form-valid-border-color);
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);
}
.was-validated .form-control-color:valid, .form-control-color.is-valid {
@@ -2687,16 +2853,16 @@ textarea.form-control-lg {
}
.was-validated .form-check-input:valid, .form-check-input.is-valid {
- border-color: #198754;
+ border-color: var(--bs-form-valid-border-color);
}
.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {
- background-color: #198754;
+ background-color: var(--bs-form-valid-color);
}
.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus {
- box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);
}
.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {
- color: #198754;
+ color: var(--bs-form-valid-color);
}
.form-check-inline .form-check-input ~ .valid-feedback {
@@ -2716,7 +2882,7 @@ textarea.form-control-lg {
width: 100%;
margin-top: 0.25rem;
font-size: 0.875em;
- color: #dc3545;
+ color: var(--bs-form-invalid-color);
}
.invalid-tooltip {
@@ -2729,8 +2895,8 @@ textarea.form-control-lg {
margin-top: 0.1rem;
font-size: 0.875rem;
color: #fff;
- background-color: rgba(220, 53, 69, 0.9);
- border-radius: 0.375rem;
+ background-color: var(--bs-danger);
+ border-radius: var(--bs-border-radius);
}
.was-validated :invalid ~ .invalid-feedback,
@@ -2741,7 +2907,7 @@ textarea.form-control-lg {
}
.was-validated .form-control:invalid, .form-control.is-invalid {
- border-color: #dc3545;
+ border-color: var(--bs-form-invalid-border-color);
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-repeat: no-repeat;
@@ -2749,8 +2915,8 @@ textarea.form-control-lg {
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {
- border-color: #dc3545;
- box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
+ border-color: var(--bs-form-invalid-border-color);
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);
}
.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {
@@ -2759,17 +2925,17 @@ textarea.form-control-lg {
}
.was-validated .form-select:invalid, .form-select.is-invalid {
- border-color: #dc3545;
+ border-color: var(--bs-form-invalid-border-color);
}
.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"] {
+ --bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
padding-right: 4.125rem;
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-position: right 0.75rem center, center right 2.25rem;
background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus {
- border-color: #dc3545;
- box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
+ border-color: var(--bs-form-invalid-border-color);
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);
}
.was-validated .form-control-color:invalid, .form-control-color.is-invalid {
@@ -2777,16 +2943,16 @@ textarea.form-control-lg {
}
.was-validated .form-check-input:invalid, .form-check-input.is-invalid {
- border-color: #dc3545;
+ border-color: var(--bs-form-invalid-border-color);
}
.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked {
- background-color: #dc3545;
+ background-color: var(--bs-form-invalid-color);
}
.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus {
- box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);
}
.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {
- color: #dc3545;
+ color: var(--bs-form-invalid-color);
}
.form-check-inline .form-check-input ~ .invalid-feedback {
@@ -2808,11 +2974,11 @@ textarea.form-control-lg {
--bs-btn-font-size: 1rem;
--bs-btn-font-weight: 400;
--bs-btn-line-height: 1.5;
- --bs-btn-color: #212529;
+ --bs-btn-color: var(--bs-body-color);
--bs-btn-bg: transparent;
- --bs-btn-border-width: 1px;
+ --bs-btn-border-width: var(--bs-border-width);
--bs-btn-border-color: transparent;
- --bs-btn-border-radius: 0.375rem;
+ --bs-btn-border-radius: var(--bs-border-radius);
--bs-btn-hover-border-color: transparent;
--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
--bs-btn-disabled-opacity: 0.65;
@@ -3162,7 +3328,7 @@ textarea.form-control-lg {
--bs-btn-active-border-color: transparent;
--bs-btn-disabled-color: #6c757d;
--bs-btn-disabled-border-color: transparent;
- --bs-btn-box-shadow: none;
+ --bs-btn-box-shadow: 0 0 0 #000;
--bs-btn-focus-shadow-rgb: 49, 132, 253;
text-decoration: underline;
}
@@ -3177,14 +3343,14 @@ textarea.form-control-lg {
--bs-btn-padding-y: 0.5rem;
--bs-btn-padding-x: 1rem;
--bs-btn-font-size: 1.25rem;
- --bs-btn-border-radius: 0.5rem;
+ --bs-btn-border-radius: var(--bs-border-radius-lg);
}
.btn-sm, .btn-group-sm > .btn {
--bs-btn-padding-y: 0.25rem;
--bs-btn-padding-x: 0.5rem;
--bs-btn-font-size: 0.875rem;
- --bs-btn-border-radius: 0.25rem;
+ --bs-btn-border-radius: var(--bs-border-radius-sm);
}
.fade {
@@ -3257,21 +3423,21 @@ textarea.form-control-lg {
--bs-dropdown-padding-y: 0.5rem;
--bs-dropdown-spacer: 0.125rem;
--bs-dropdown-font-size: 1rem;
- --bs-dropdown-color: #212529;
- --bs-dropdown-bg: #fff;
+ --bs-dropdown-color: var(--bs-body-color);
+ --bs-dropdown-bg: var(--bs-body-bg);
--bs-dropdown-border-color: var(--bs-border-color-translucent);
- --bs-dropdown-border-radius: 0.375rem;
- --bs-dropdown-border-width: 1px;
- --bs-dropdown-inner-border-radius: calc(0.375rem - 1px);
+ --bs-dropdown-border-radius: var(--bs-border-radius);
+ --bs-dropdown-border-width: var(--bs-border-width);
+ --bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));
--bs-dropdown-divider-bg: var(--bs-border-color-translucent);
--bs-dropdown-divider-margin-y: 0.5rem;
--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
- --bs-dropdown-link-color: #212529;
- --bs-dropdown-link-hover-color: #1e2125;
- --bs-dropdown-link-hover-bg: #e9ecef;
+ --bs-dropdown-link-color: var(--bs-body-color);
+ --bs-dropdown-link-hover-color: var(--bs-body-color);
+ --bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);
--bs-dropdown-link-active-color: #fff;
--bs-dropdown-link-active-bg: #0d6efd;
- --bs-dropdown-link-disabled-color: #adb5bd;
+ --bs-dropdown-link-disabled-color: var(--bs-tertiary-color);
--bs-dropdown-item-padding-x: 1rem;
--bs-dropdown-item-padding-y: 0.25rem;
--bs-dropdown-header-color: #6c757d;
@@ -3490,6 +3656,7 @@ textarea.form-control-lg {
white-space: nowrap;
background-color: transparent;
border: 0;
+ border-radius: var(--bs-dropdown-item-border-radius, 0);
}
.dropdown-item:hover, .dropdown-item:focus {
color: var(--bs-dropdown-link-hover-color);
@@ -3576,11 +3743,11 @@ textarea.form-control-lg {
}
.btn-group {
- border-radius: 0.375rem;
+ border-radius: var(--bs-border-radius);
}
.btn-group > :not(.btn-check:first-child) + .btn,
.btn-group > .btn-group:not(:first-child) {
- margin-left: -1px;
+ margin-left: calc(var(--bs-border-width) * -1);
}
.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
.btn-group > .btn.dropdown-toggle-split:first-child,
@@ -3627,7 +3794,7 @@ textarea.form-control-lg {
}
.btn-group-vertical > .btn:not(:first-child),
.btn-group-vertical > .btn-group:not(:first-child) {
- margin-top: -1px;
+ margin-top: calc(var(--bs-border-width) * -1);
}
.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
.btn-group-vertical > .btn-group:not(:last-child) > .btn {
@@ -3646,7 +3813,7 @@ textarea.form-control-lg {
--bs-nav-link-font-weight: ;
--bs-nav-link-color: var(--bs-link-color);
--bs-nav-link-hover-color: var(--bs-link-hover-color);
- --bs-nav-link-disabled-color: #6c757d;
+ --bs-nav-link-disabled-color: var(--bs-secondary-color);
display: flex;
flex-wrap: wrap;
padding-left: 0;
@@ -3661,6 +3828,8 @@ textarea.form-control-lg {
font-weight: var(--bs-nav-link-font-weight);
color: var(--bs-nav-link-color);
text-decoration: none;
+ background: none;
+ border: 0;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
@@ -3671,25 +3840,28 @@ textarea.form-control-lg {
.nav-link:hover, .nav-link:focus {
color: var(--bs-nav-link-hover-color);
}
-.nav-link.disabled {
+.nav-link:focus-visible {
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+.nav-link.disabled, .nav-link:disabled {
color: var(--bs-nav-link-disabled-color);
pointer-events: none;
cursor: default;
}
.nav-tabs {
- --bs-nav-tabs-border-width: 1px;
- --bs-nav-tabs-border-color: #dee2e6;
- --bs-nav-tabs-border-radius: 0.375rem;
- --bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;
- --bs-nav-tabs-link-active-color: #495057;
- --bs-nav-tabs-link-active-bg: #fff;
- --bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #fff;
+ --bs-nav-tabs-border-width: var(--bs-border-width);
+ --bs-nav-tabs-border-color: var(--bs-border-color);
+ --bs-nav-tabs-border-radius: var(--bs-border-radius);
+ --bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);
+ --bs-nav-tabs-link-active-color: var(--bs-emphasis-color);
+ --bs-nav-tabs-link-active-bg: var(--bs-body-bg);
+ --bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);
border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color);
}
.nav-tabs .nav-link {
margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width));
- background: none;
border: var(--bs-nav-tabs-border-width) solid transparent;
border-top-left-radius: var(--bs-nav-tabs-border-radius);
border-top-right-radius: var(--bs-nav-tabs-border-radius);
@@ -3698,11 +3870,6 @@ textarea.form-control-lg {
isolation: isolate;
border-color: var(--bs-nav-tabs-link-hover-border-color);
}
-.nav-tabs .nav-link.disabled, .nav-tabs .nav-link:disabled {
- color: var(--bs-nav-link-disabled-color);
- background-color: transparent;
- border-color: transparent;
-}
.nav-tabs .nav-link.active,
.nav-tabs .nav-item.show .nav-link {
color: var(--bs-nav-tabs-link-active-color);
@@ -3716,26 +3883,40 @@ textarea.form-control-lg {
}
.nav-pills {
- --bs-nav-pills-border-radius: 0.375rem;
+ --bs-nav-pills-border-radius: var(--bs-border-radius);
--bs-nav-pills-link-active-color: #fff;
--bs-nav-pills-link-active-bg: #0d6efd;
}
.nav-pills .nav-link {
- background: none;
- border: 0;
border-radius: var(--bs-nav-pills-border-radius);
}
-.nav-pills .nav-link:disabled {
- color: var(--bs-nav-link-disabled-color);
- background-color: transparent;
- border-color: transparent;
-}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
color: var(--bs-nav-pills-link-active-color);
background-color: var(--bs-nav-pills-link-active-bg);
}
+.nav-underline {
+ --bs-nav-underline-gap: 1rem;
+ --bs-nav-underline-border-width: 0.125rem;
+ --bs-nav-underline-link-active-color: var(--bs-emphasis-color);
+ gap: var(--bs-nav-underline-gap);
+}
+.nav-underline .nav-link {
+ padding-right: 0;
+ padding-left: 0;
+ border-bottom: var(--bs-nav-underline-border-width) solid transparent;
+}
+.nav-underline .nav-link:hover, .nav-underline .nav-link:focus {
+ border-bottom-color: currentcolor;
+}
+.nav-underline .nav-link.active,
+.nav-underline .show > .nav-link {
+ font-weight: 700;
+ color: var(--bs-nav-underline-link-active-color);
+ border-bottom-color: currentcolor;
+}
+
.nav-fill > .nav-link,
.nav-fill .nav-item {
flex: 1 1 auto;
@@ -3764,22 +3945,22 @@ textarea.form-control-lg {
.navbar {
--bs-navbar-padding-x: 0;
--bs-navbar-padding-y: 0.5rem;
- --bs-navbar-color: rgba(0, 0, 0, 0.55);
- --bs-navbar-hover-color: rgba(0, 0, 0, 0.7);
- --bs-navbar-disabled-color: rgba(0, 0, 0, 0.3);
- --bs-navbar-active-color: rgba(0, 0, 0, 0.9);
+ --bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65);
+ --bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8);
+ --bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3);
+ --bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);
--bs-navbar-brand-padding-y: 0.3125rem;
--bs-navbar-brand-margin-end: 1rem;
--bs-navbar-brand-font-size: 1.25rem;
- --bs-navbar-brand-color: rgba(0, 0, 0, 0.9);
- --bs-navbar-brand-hover-color: rgba(0, 0, 0, 0.9);
+ --bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);
+ --bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);
--bs-navbar-nav-link-padding-x: 0.5rem;
--bs-navbar-toggler-padding-y: 0.25rem;
--bs-navbar-toggler-padding-x: 0.75rem;
--bs-navbar-toggler-font-size: 1.25rem;
- --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
- --bs-navbar-toggler-border-color: rgba(0, 0, 0, 0.1);
- --bs-navbar-toggler-border-radius: 0.375rem;
+ --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
+ --bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15);
+ --bs-navbar-toggler-border-radius: var(--bs-border-radius);
--bs-navbar-toggler-focus-width: 0.25rem;
--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;
position: relative;
@@ -3827,8 +4008,7 @@ textarea.form-control-lg {
margin-bottom: 0;
list-style: none;
}
-.navbar-nav .show > .nav-link,
-.navbar-nav .nav-link.active {
+.navbar-nav .nav-link.active, .navbar-nav .nav-link.show {
color: var(--bs-navbar-active-color);
}
.navbar-nav .dropdown-menu {
@@ -4173,7 +4353,8 @@ textarea.form-control-lg {
overflow-y: visible;
}
-.navbar-dark {
+.navbar-dark,
+.navbar[data-bs-theme=dark] {
--bs-navbar-color: rgba(255, 255, 255, 0.55);
--bs-navbar-hover-color: rgba(255, 255, 255, 0.75);
--bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);
@@ -4184,22 +4365,28 @@ textarea.form-control-lg {
--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
+[data-bs-theme=dark] .navbar-toggler-icon {
+ --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
+}
+
.card {
--bs-card-spacer-y: 1rem;
--bs-card-spacer-x: 1rem;
--bs-card-title-spacer-y: 0.5rem;
- --bs-card-border-width: 1px;
+ --bs-card-title-color: ;
+ --bs-card-subtitle-color: ;
+ --bs-card-border-width: var(--bs-border-width);
--bs-card-border-color: var(--bs-border-color-translucent);
- --bs-card-border-radius: 0.375rem;
+ --bs-card-border-radius: var(--bs-border-radius);
--bs-card-box-shadow: ;
- --bs-card-inner-border-radius: calc(0.375rem - 1px);
+ --bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));
--bs-card-cap-padding-y: 0.5rem;
--bs-card-cap-padding-x: 1rem;
- --bs-card-cap-bg: rgba(0, 0, 0, 0.03);
+ --bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03);
--bs-card-cap-color: ;
--bs-card-height: ;
--bs-card-color: ;
- --bs-card-bg: #fff;
+ --bs-card-bg: var(--bs-body-bg);
--bs-card-img-overlay-padding: 1rem;
--bs-card-group-margin: 0.75rem;
position: relative;
@@ -4207,6 +4394,7 @@ textarea.form-control-lg {
flex-direction: column;
min-width: 0;
height: var(--bs-card-height);
+ color: var(--bs-body-color);
word-wrap: break-word;
background-color: var(--bs-card-bg);
background-clip: border-box;
@@ -4244,11 +4432,13 @@ textarea.form-control-lg {
.card-title {
margin-bottom: var(--bs-card-title-spacer-y);
+ color: var(--bs-card-title-color);
}
.card-subtitle {
margin-top: calc(-0.5 * var(--bs-card-title-spacer-y));
margin-bottom: 0;
+ color: var(--bs-card-subtitle-color);
}
.card-text:last-child {
@@ -4345,11 +4535,11 @@ textarea.form-control-lg {
border-bottom-right-radius: 0;
}
.card-group > .card:not(:last-child) .card-img-top,
-.card-group > .card:not(:last-child) .card-header {
+ .card-group > .card:not(:last-child) .card-header {
border-top-right-radius: 0;
}
.card-group > .card:not(:last-child) .card-img-bottom,
-.card-group > .card:not(:last-child) .card-footer {
+ .card-group > .card:not(:last-child) .card-footer {
border-bottom-right-radius: 0;
}
.card-group > .card:not(:first-child) {
@@ -4357,38 +4547,38 @@ textarea.form-control-lg {
border-bottom-left-radius: 0;
}
.card-group > .card:not(:first-child) .card-img-top,
-.card-group > .card:not(:first-child) .card-header {
+ .card-group > .card:not(:first-child) .card-header {
border-top-left-radius: 0;
}
.card-group > .card:not(:first-child) .card-img-bottom,
-.card-group > .card:not(:first-child) .card-footer {
+ .card-group > .card:not(:first-child) .card-footer {
border-bottom-left-radius: 0;
}
}
.accordion {
- --bs-accordion-color: #212529;
- --bs-accordion-bg: #fff;
+ --bs-accordion-color: var(--bs-body-color);
+ --bs-accordion-bg: var(--bs-body-bg);
--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;
--bs-accordion-border-color: var(--bs-border-color);
- --bs-accordion-border-width: 1px;
- --bs-accordion-border-radius: 0.375rem;
- --bs-accordion-inner-border-radius: calc(0.375rem - 1px);
+ --bs-accordion-border-width: var(--bs-border-width);
+ --bs-accordion-border-radius: var(--bs-border-radius);
+ --bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));
--bs-accordion-btn-padding-x: 1.25rem;
--bs-accordion-btn-padding-y: 1rem;
- --bs-accordion-btn-color: #212529;
+ --bs-accordion-btn-color: var(--bs-body-color);
--bs-accordion-btn-bg: var(--bs-accordion-bg);
--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
--bs-accordion-btn-icon-width: 1.25rem;
--bs-accordion-btn-icon-transform: rotate(-180deg);
--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;
- --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+ --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
--bs-accordion-btn-focus-border-color: #86b7fe;
--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
--bs-accordion-body-padding-x: 1.25rem;
--bs-accordion-body-padding-y: 1rem;
- --bs-accordion-active-color: #0c63e4;
- --bs-accordion-active-bg: #e7f1ff;
+ --bs-accordion-active-color: var(--bs-primary-text-emphasis);
+ --bs-accordion-active-bg: var(--bs-primary-bg-subtle);
}
.accordion-button {
@@ -4501,15 +4691,20 @@ textarea.form-control-lg {
border-radius: 0;
}
+[data-bs-theme=dark] .accordion-button::after {
+ --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+ --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+}
+
.breadcrumb {
--bs-breadcrumb-padding-x: 0;
--bs-breadcrumb-padding-y: 0;
--bs-breadcrumb-margin-bottom: 1rem;
--bs-breadcrumb-bg: ;
--bs-breadcrumb-border-radius: ;
- --bs-breadcrumb-divider-color: #6c757d;
+ --bs-breadcrumb-divider-color: var(--bs-secondary-color);
--bs-breadcrumb-item-padding-x: 0.5rem;
- --bs-breadcrumb-item-active-color: #6c757d;
+ --bs-breadcrumb-item-active-color: var(--bs-secondary-color);
display: flex;
flex-wrap: wrap;
padding: var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);
@@ -4538,22 +4733,22 @@ textarea.form-control-lg {
--bs-pagination-padding-y: 0.375rem;
--bs-pagination-font-size: 1rem;
--bs-pagination-color: var(--bs-link-color);
- --bs-pagination-bg: #fff;
- --bs-pagination-border-width: 1px;
- --bs-pagination-border-color: #dee2e6;
- --bs-pagination-border-radius: 0.375rem;
+ --bs-pagination-bg: var(--bs-body-bg);
+ --bs-pagination-border-width: var(--bs-border-width);
+ --bs-pagination-border-color: var(--bs-border-color);
+ --bs-pagination-border-radius: var(--bs-border-radius);
--bs-pagination-hover-color: var(--bs-link-hover-color);
- --bs-pagination-hover-bg: #e9ecef;
- --bs-pagination-hover-border-color: #dee2e6;
+ --bs-pagination-hover-bg: var(--bs-tertiary-bg);
+ --bs-pagination-hover-border-color: var(--bs-border-color);
--bs-pagination-focus-color: var(--bs-link-hover-color);
- --bs-pagination-focus-bg: #e9ecef;
+ --bs-pagination-focus-bg: var(--bs-secondary-bg);
--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
--bs-pagination-active-color: #fff;
--bs-pagination-active-bg: #0d6efd;
--bs-pagination-active-border-color: #0d6efd;
- --bs-pagination-disabled-color: #6c757d;
- --bs-pagination-disabled-bg: #fff;
- --bs-pagination-disabled-border-color: #dee2e6;
+ --bs-pagination-disabled-color: var(--bs-secondary-color);
+ --bs-pagination-disabled-bg: var(--bs-secondary-bg);
+ --bs-pagination-disabled-border-color: var(--bs-border-color);
display: flex;
padding-left: 0;
list-style: none;
@@ -4602,7 +4797,7 @@ textarea.form-control-lg {
}
.page-item:not(:first-child) .page-link {
- margin-left: -1px;
+ margin-left: calc(var(--bs-border-width) * -1);
}
.page-item:first-child .page-link {
border-top-left-radius: var(--bs-pagination-border-radius);
@@ -4617,14 +4812,14 @@ textarea.form-control-lg {
--bs-pagination-padding-x: 1.5rem;
--bs-pagination-padding-y: 0.75rem;
--bs-pagination-font-size: 1.25rem;
- --bs-pagination-border-radius: 0.5rem;
+ --bs-pagination-border-radius: var(--bs-border-radius-lg);
}
.pagination-sm {
--bs-pagination-padding-x: 0.5rem;
--bs-pagination-padding-y: 0.25rem;
--bs-pagination-font-size: 0.875rem;
- --bs-pagination-border-radius: 0.25rem;
+ --bs-pagination-border-radius: var(--bs-border-radius-sm);
}
.badge {
@@ -4633,7 +4828,7 @@ textarea.form-control-lg {
--bs-badge-font-size: 0.75em;
--bs-badge-font-weight: 700;
--bs-badge-color: #fff;
- --bs-badge-border-radius: 0.375rem;
+ --bs-badge-border-radius: var(--bs-border-radius);
display: inline-block;
padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x);
font-size: var(--bs-badge-font-size);
@@ -4661,8 +4856,9 @@ textarea.form-control-lg {
--bs-alert-margin-bottom: 1rem;
--bs-alert-color: inherit;
--bs-alert-border-color: transparent;
- --bs-alert-border: 1px solid var(--bs-alert-border-color);
- --bs-alert-border-radius: 0.375rem;
+ --bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);
+ --bs-alert-border-radius: var(--bs-border-radius);
+ --bs-alert-link-color: inherit;
position: relative;
padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x);
margin-bottom: var(--bs-alert-margin-bottom);
@@ -4678,6 +4874,7 @@ textarea.form-control-lg {
.alert-link {
font-weight: 700;
+ color: var(--bs-alert-link-color);
}
.alert-dismissible {
@@ -4692,75 +4889,59 @@ textarea.form-control-lg {
}
.alert-primary {
- --bs-alert-color: #084298;
- --bs-alert-bg: #cfe2ff;
- --bs-alert-border-color: #b6d4fe;
-}
-.alert-primary .alert-link {
- color: #06357a;
+ --bs-alert-color: var(--bs-primary-text-emphasis);
+ --bs-alert-bg: var(--bs-primary-bg-subtle);
+ --bs-alert-border-color: var(--bs-primary-border-subtle);
+ --bs-alert-link-color: var(--bs-primary-text-emphasis);
}
.alert-secondary {
- --bs-alert-color: #41464b;
- --bs-alert-bg: #e2e3e5;
- --bs-alert-border-color: #d3d6d8;
-}
-.alert-secondary .alert-link {
- color: #34383c;
+ --bs-alert-color: var(--bs-secondary-text-emphasis);
+ --bs-alert-bg: var(--bs-secondary-bg-subtle);
+ --bs-alert-border-color: var(--bs-secondary-border-subtle);
+ --bs-alert-link-color: var(--bs-secondary-text-emphasis);
}
.alert-success {
- --bs-alert-color: #0f5132;
- --bs-alert-bg: #d1e7dd;
- --bs-alert-border-color: #badbcc;
-}
-.alert-success .alert-link {
- color: #0c4128;
+ --bs-alert-color: var(--bs-success-text-emphasis);
+ --bs-alert-bg: var(--bs-success-bg-subtle);
+ --bs-alert-border-color: var(--bs-success-border-subtle);
+ --bs-alert-link-color: var(--bs-success-text-emphasis);
}
.alert-info {
- --bs-alert-color: #055160;
- --bs-alert-bg: #cff4fc;
- --bs-alert-border-color: #b6effb;
-}
-.alert-info .alert-link {
- color: #04414d;
+ --bs-alert-color: var(--bs-info-text-emphasis);
+ --bs-alert-bg: var(--bs-info-bg-subtle);
+ --bs-alert-border-color: var(--bs-info-border-subtle);
+ --bs-alert-link-color: var(--bs-info-text-emphasis);
}
.alert-warning {
- --bs-alert-color: #664d03;
- --bs-alert-bg: #fff3cd;
- --bs-alert-border-color: #ffecb5;
-}
-.alert-warning .alert-link {
- color: #523e02;
+ --bs-alert-color: var(--bs-warning-text-emphasis);
+ --bs-alert-bg: var(--bs-warning-bg-subtle);
+ --bs-alert-border-color: var(--bs-warning-border-subtle);
+ --bs-alert-link-color: var(--bs-warning-text-emphasis);
}
.alert-danger {
- --bs-alert-color: #842029;
- --bs-alert-bg: #f8d7da;
- --bs-alert-border-color: #f5c2c7;
-}
-.alert-danger .alert-link {
- color: #6a1a21;
+ --bs-alert-color: var(--bs-danger-text-emphasis);
+ --bs-alert-bg: var(--bs-danger-bg-subtle);
+ --bs-alert-border-color: var(--bs-danger-border-subtle);
+ --bs-alert-link-color: var(--bs-danger-text-emphasis);
}
.alert-light {
- --bs-alert-color: #636464;
- --bs-alert-bg: #fefefe;
- --bs-alert-border-color: #fdfdfe;
-}
-.alert-light .alert-link {
- color: #4f5050;
+ --bs-alert-color: var(--bs-light-text-emphasis);
+ --bs-alert-bg: var(--bs-light-bg-subtle);
+ --bs-alert-border-color: var(--bs-light-border-subtle);
+ --bs-alert-link-color: var(--bs-light-text-emphasis);
}
.alert-dark {
- --bs-alert-color: #141619;
- --bs-alert-bg: #d3d3d4;
- --bs-alert-border-color: #bcbebf;
-}
-.alert-dark .alert-link {
- color: #101214;
+ --bs-alert-color: var(--bs-dark-text-emphasis);
+ --bs-alert-bg: var(--bs-dark-bg-subtle);
+ --bs-alert-border-color: var(--bs-dark-border-subtle);
+ --bs-alert-link-color: var(--bs-dark-text-emphasis);
}
@keyframes progress-bar-stripes {
@@ -4768,12 +4949,13 @@ textarea.form-control-lg {
background-position-x: 1rem;
}
}
-.progress {
+.progress,
+.progress-stacked {
--bs-progress-height: 1rem;
--bs-progress-font-size: 0.75rem;
- --bs-progress-bg: #e9ecef;
- --bs-progress-border-radius: 0.375rem;
- --bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);
+ --bs-progress-bg: var(--bs-secondary-bg);
+ --bs-progress-border-radius: var(--bs-border-radius);
+ --bs-progress-box-shadow: var(--bs-box-shadow-inset);
--bs-progress-bar-color: #fff;
--bs-progress-bar-bg: #0d6efd;
--bs-progress-bar-transition: width 0.6s ease;
@@ -4807,6 +4989,14 @@ textarea.form-control-lg {
background-size: var(--bs-progress-height) var(--bs-progress-height);
}
+.progress-stacked > .progress {
+ overflow: visible;
+}
+
+.progress-stacked > .progress > .progress-bar {
+ width: 100%;
+}
+
.progress-bar-animated {
animation: 1s linear infinite progress-bar-stripes;
}
@@ -4817,20 +5007,20 @@ textarea.form-control-lg {
}
.list-group {
- --bs-list-group-color: #212529;
- --bs-list-group-bg: #fff;
- --bs-list-group-border-color: rgba(0, 0, 0, 0.125);
- --bs-list-group-border-width: 1px;
- --bs-list-group-border-radius: 0.375rem;
+ --bs-list-group-color: var(--bs-body-color);
+ --bs-list-group-bg: var(--bs-body-bg);
+ --bs-list-group-border-color: var(--bs-border-color);
+ --bs-list-group-border-width: var(--bs-border-width);
+ --bs-list-group-border-radius: var(--bs-border-radius);
--bs-list-group-item-padding-x: 1rem;
--bs-list-group-item-padding-y: 0.5rem;
- --bs-list-group-action-color: #495057;
- --bs-list-group-action-hover-color: #495057;
- --bs-list-group-action-hover-bg: #f8f9fa;
- --bs-list-group-action-active-color: #212529;
- --bs-list-group-action-active-bg: #e9ecef;
- --bs-list-group-disabled-color: #6c757d;
- --bs-list-group-disabled-bg: #fff;
+ --bs-list-group-action-color: var(--bs-secondary-color);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-tertiary-bg);
+ --bs-list-group-action-active-color: var(--bs-body-color);
+ --bs-list-group-action-active-bg: var(--bs-secondary-bg);
+ --bs-list-group-disabled-color: var(--bs-secondary-color);
+ --bs-list-group-disabled-bg: var(--bs-body-bg);
--bs-list-group-active-color: #fff;
--bs-list-group-active-bg: #0d6efd;
--bs-list-group-active-border-color: #0d6efd;
@@ -5056,148 +5246,152 @@ textarea.form-control-lg {
}
.list-group-item-primary {
- color: #084298;
- background-color: #cfe2ff;
-}
-.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {
- color: #084298;
- background-color: #bacbe6;
-}
-.list-group-item-primary.list-group-item-action.active {
- color: #fff;
- background-color: #084298;
- border-color: #084298;
+ --bs-list-group-color: var(--bs-primary-text-emphasis);
+ --bs-list-group-bg: var(--bs-primary-bg-subtle);
+ --bs-list-group-border-color: var(--bs-primary-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-primary-border-subtle);
+ --bs-list-group-active-color: var(--bs-primary-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-primary-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-primary-text-emphasis);
}
.list-group-item-secondary {
- color: #41464b;
- background-color: #e2e3e5;
-}
-.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {
- color: #41464b;
- background-color: #cbccce;
-}
-.list-group-item-secondary.list-group-item-action.active {
- color: #fff;
- background-color: #41464b;
- border-color: #41464b;
+ --bs-list-group-color: var(--bs-secondary-text-emphasis);
+ --bs-list-group-bg: var(--bs-secondary-bg-subtle);
+ --bs-list-group-border-color: var(--bs-secondary-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);
+ --bs-list-group-active-color: var(--bs-secondary-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-secondary-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-secondary-text-emphasis);
}
.list-group-item-success {
- color: #0f5132;
- background-color: #d1e7dd;
-}
-.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {
- color: #0f5132;
- background-color: #bcd0c7;
-}
-.list-group-item-success.list-group-item-action.active {
- color: #fff;
- background-color: #0f5132;
- border-color: #0f5132;
+ --bs-list-group-color: var(--bs-success-text-emphasis);
+ --bs-list-group-bg: var(--bs-success-bg-subtle);
+ --bs-list-group-border-color: var(--bs-success-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-success-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-success-border-subtle);
+ --bs-list-group-active-color: var(--bs-success-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-success-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-success-text-emphasis);
}
.list-group-item-info {
- color: #055160;
- background-color: #cff4fc;
-}
-.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {
- color: #055160;
- background-color: #badce3;
-}
-.list-group-item-info.list-group-item-action.active {
- color: #fff;
- background-color: #055160;
- border-color: #055160;
+ --bs-list-group-color: var(--bs-info-text-emphasis);
+ --bs-list-group-bg: var(--bs-info-bg-subtle);
+ --bs-list-group-border-color: var(--bs-info-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-info-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-info-border-subtle);
+ --bs-list-group-active-color: var(--bs-info-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-info-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-info-text-emphasis);
}
.list-group-item-warning {
- color: #664d03;
- background-color: #fff3cd;
-}
-.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {
- color: #664d03;
- background-color: #e6dbb9;
-}
-.list-group-item-warning.list-group-item-action.active {
- color: #fff;
- background-color: #664d03;
- border-color: #664d03;
+ --bs-list-group-color: var(--bs-warning-text-emphasis);
+ --bs-list-group-bg: var(--bs-warning-bg-subtle);
+ --bs-list-group-border-color: var(--bs-warning-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-warning-border-subtle);
+ --bs-list-group-active-color: var(--bs-warning-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-warning-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-warning-text-emphasis);
}
.list-group-item-danger {
- color: #842029;
- background-color: #f8d7da;
-}
-.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {
- color: #842029;
- background-color: #dfc2c4;
-}
-.list-group-item-danger.list-group-item-action.active {
- color: #fff;
- background-color: #842029;
- border-color: #842029;
+ --bs-list-group-color: var(--bs-danger-text-emphasis);
+ --bs-list-group-bg: var(--bs-danger-bg-subtle);
+ --bs-list-group-border-color: var(--bs-danger-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-danger-border-subtle);
+ --bs-list-group-active-color: var(--bs-danger-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-danger-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-danger-text-emphasis);
}
.list-group-item-light {
- color: #636464;
- background-color: #fefefe;
-}
-.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {
- color: #636464;
- background-color: #e5e5e5;
-}
-.list-group-item-light.list-group-item-action.active {
- color: #fff;
- background-color: #636464;
- border-color: #636464;
+ --bs-list-group-color: var(--bs-light-text-emphasis);
+ --bs-list-group-bg: var(--bs-light-bg-subtle);
+ --bs-list-group-border-color: var(--bs-light-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-light-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-light-border-subtle);
+ --bs-list-group-active-color: var(--bs-light-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-light-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-light-text-emphasis);
}
.list-group-item-dark {
- color: #141619;
- background-color: #d3d3d4;
-}
-.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {
- color: #141619;
- background-color: #bebebf;
-}
-.list-group-item-dark.list-group-item-action.active {
- color: #fff;
- background-color: #141619;
- border-color: #141619;
+ --bs-list-group-color: var(--bs-dark-text-emphasis);
+ --bs-list-group-bg: var(--bs-dark-bg-subtle);
+ --bs-list-group-border-color: var(--bs-dark-border-subtle);
+ --bs-list-group-action-hover-color: var(--bs-emphasis-color);
+ --bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);
+ --bs-list-group-action-active-color: var(--bs-emphasis-color);
+ --bs-list-group-action-active-bg: var(--bs-dark-border-subtle);
+ --bs-list-group-active-color: var(--bs-dark-bg-subtle);
+ --bs-list-group-active-bg: var(--bs-dark-text-emphasis);
+ --bs-list-group-active-border-color: var(--bs-dark-text-emphasis);
}
.btn-close {
+ --bs-btn-close-color: #000;
+ --bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");
+ --bs-btn-close-opacity: 0.5;
+ --bs-btn-close-hover-opacity: 0.75;
+ --bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+ --bs-btn-close-focus-opacity: 1;
+ --bs-btn-close-disabled-opacity: 0.25;
+ --bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);
box-sizing: content-box;
width: 1em;
height: 1em;
padding: 0.25em 0.25em;
- color: #000;
- background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
+ color: var(--bs-btn-close-color);
+ background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat;
border: 0;
border-radius: 0.375rem;
- opacity: 0.5;
+ opacity: var(--bs-btn-close-opacity);
}
.btn-close:hover {
- color: #000;
+ color: var(--bs-btn-close-color);
text-decoration: none;
- opacity: 0.75;
+ opacity: var(--bs-btn-close-hover-opacity);
}
.btn-close:focus {
outline: 0;
- box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
- opacity: 1;
+ box-shadow: var(--bs-btn-close-focus-shadow);
+ opacity: var(--bs-btn-close-focus-opacity);
}
.btn-close:disabled, .btn-close.disabled {
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
- opacity: 0.25;
+ opacity: var(--bs-btn-close-disabled-opacity);
}
.btn-close-white {
- filter: invert(1) grayscale(100%) brightness(200%);
+ filter: var(--bs-btn-close-white-filter);
+}
+
+[data-bs-theme=dark] .btn-close {
+ filter: var(--bs-btn-close-white-filter);
}
.toast {
@@ -5208,14 +5402,14 @@ textarea.form-control-lg {
--bs-toast-max-width: 350px;
--bs-toast-font-size: 0.875rem;
--bs-toast-color: ;
- --bs-toast-bg: rgba(255, 255, 255, 0.85);
- --bs-toast-border-width: 1px;
+ --bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85);
+ --bs-toast-border-width: var(--bs-border-width);
--bs-toast-border-color: var(--bs-border-color-translucent);
- --bs-toast-border-radius: 0.375rem;
- --bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
- --bs-toast-header-color: #6c757d;
- --bs-toast-header-bg: rgba(255, 255, 255, 0.85);
- --bs-toast-header-border-color: rgba(0, 0, 0, 0.05);
+ --bs-toast-border-radius: var(--bs-border-radius);
+ --bs-toast-box-shadow: var(--bs-box-shadow);
+ --bs-toast-header-color: var(--bs-secondary-color);
+ --bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85);
+ --bs-toast-header-border-color: var(--bs-border-color-translucent);
width: var(--bs-toast-max-width);
max-width: 100%;
font-size: var(--bs-toast-font-size);
@@ -5275,22 +5469,22 @@ textarea.form-control-lg {
--bs-modal-padding: 1rem;
--bs-modal-margin: 0.5rem;
--bs-modal-color: ;
- --bs-modal-bg: #fff;
+ --bs-modal-bg: var(--bs-body-bg);
--bs-modal-border-color: var(--bs-border-color-translucent);
- --bs-modal-border-width: 1px;
- --bs-modal-border-radius: 0.5rem;
+ --bs-modal-border-width: var(--bs-border-width);
+ --bs-modal-border-radius: var(--bs-border-radius-lg);
--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
- --bs-modal-inner-border-radius: calc(0.5rem - 1px);
+ --bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));
--bs-modal-header-padding-x: 1rem;
--bs-modal-header-padding-y: 1rem;
--bs-modal-header-padding: 1rem 1rem;
--bs-modal-header-border-color: var(--bs-border-color);
- --bs-modal-header-border-width: 1px;
+ --bs-modal-header-border-width: var(--bs-border-width);
--bs-modal-title-line-height: 1.5;
--bs-modal-footer-gap: 0.5rem;
--bs-modal-footer-bg: ;
--bs-modal-footer-border-color: var(--bs-border-color);
- --bs-modal-footer-border-width: 1px;
+ --bs-modal-footer-border-width: var(--bs-border-width);
position: fixed;
top: 0;
left: 0;
@@ -5433,7 +5627,7 @@ textarea.form-control-lg {
}
@media (min-width: 992px) {
.modal-lg,
-.modal-xl {
+ .modal-xl {
--bs-modal-width: 800px;
}
}
@@ -5474,7 +5668,7 @@ textarea.form-control-lg {
border-radius: 0;
}
.modal-fullscreen-sm-down .modal-header,
-.modal-fullscreen-sm-down .modal-footer {
+ .modal-fullscreen-sm-down .modal-footer {
border-radius: 0;
}
.modal-fullscreen-sm-down .modal-body {
@@ -5494,7 +5688,7 @@ textarea.form-control-lg {
border-radius: 0;
}
.modal-fullscreen-md-down .modal-header,
-.modal-fullscreen-md-down .modal-footer {
+ .modal-fullscreen-md-down .modal-footer {
border-radius: 0;
}
.modal-fullscreen-md-down .modal-body {
@@ -5514,7 +5708,7 @@ textarea.form-control-lg {
border-radius: 0;
}
.modal-fullscreen-lg-down .modal-header,
-.modal-fullscreen-lg-down .modal-footer {
+ .modal-fullscreen-lg-down .modal-footer {
border-radius: 0;
}
.modal-fullscreen-lg-down .modal-body {
@@ -5534,7 +5728,7 @@ textarea.form-control-lg {
border-radius: 0;
}
.modal-fullscreen-xl-down .modal-header,
-.modal-fullscreen-xl-down .modal-footer {
+ .modal-fullscreen-xl-down .modal-footer {
border-radius: 0;
}
.modal-fullscreen-xl-down .modal-body {
@@ -5554,7 +5748,7 @@ textarea.form-control-lg {
border-radius: 0;
}
.modal-fullscreen-xxl-down .modal-header,
-.modal-fullscreen-xxl-down .modal-footer {
+ .modal-fullscreen-xxl-down .modal-footer {
border-radius: 0;
}
.modal-fullscreen-xxl-down .modal-body {
@@ -5568,15 +5762,14 @@ textarea.form-control-lg {
--bs-tooltip-padding-y: 0.25rem;
--bs-tooltip-margin: ;
--bs-tooltip-font-size: 0.875rem;
- --bs-tooltip-color: #fff;
- --bs-tooltip-bg: #000;
- --bs-tooltip-border-radius: 0.375rem;
+ --bs-tooltip-color: var(--bs-body-bg);
+ --bs-tooltip-bg: var(--bs-emphasis-color);
+ --bs-tooltip-border-radius: var(--bs-border-radius);
--bs-tooltip-opacity: 0.9;
--bs-tooltip-arrow-width: 0.8rem;
--bs-tooltip-arrow-height: 0.4rem;
z-index: var(--bs-tooltip-zindex);
display: block;
- padding: var(--bs-tooltip-arrow-height);
margin: var(--bs-tooltip-margin);
font-family: var(--bs-font-sans-serif);
font-style: normal;
@@ -5612,7 +5805,7 @@ textarea.form-control-lg {
}
.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow {
- bottom: 0;
+ bottom: calc(-1 * var(--bs-tooltip-arrow-height));
}
.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before {
top: -1px;
@@ -5622,7 +5815,7 @@ textarea.form-control-lg {
/* rtl:begin:ignore */
.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow {
- left: 0;
+ left: calc(-1 * var(--bs-tooltip-arrow-height));
width: var(--bs-tooltip-arrow-height);
height: var(--bs-tooltip-arrow-width);
}
@@ -5634,7 +5827,7 @@ textarea.form-control-lg {
/* rtl:end:ignore */
.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow {
- top: 0;
+ top: calc(-1 * var(--bs-tooltip-arrow-height));
}
.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before {
bottom: -1px;
@@ -5644,7 +5837,7 @@ textarea.form-control-lg {
/* rtl:begin:ignore */
.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow {
- right: 0;
+ right: calc(-1 * var(--bs-tooltip-arrow-height));
width: var(--bs-tooltip-arrow-height);
height: var(--bs-tooltip-arrow-width);
}
@@ -5668,20 +5861,20 @@ textarea.form-control-lg {
--bs-popover-zindex: 1070;
--bs-popover-max-width: 276px;
--bs-popover-font-size: 0.875rem;
- --bs-popover-bg: #fff;
- --bs-popover-border-width: 1px;
+ --bs-popover-bg: var(--bs-body-bg);
+ --bs-popover-border-width: var(--bs-border-width);
--bs-popover-border-color: var(--bs-border-color-translucent);
- --bs-popover-border-radius: 0.5rem;
- --bs-popover-inner-border-radius: calc(0.5rem - 1px);
+ --bs-popover-border-radius: var(--bs-border-radius-lg);
+ --bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));
--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-popover-header-padding-x: 1rem;
--bs-popover-header-padding-y: 0.5rem;
--bs-popover-header-font-size: 1rem;
- --bs-popover-header-color: ;
- --bs-popover-header-bg: #f0f0f0;
+ --bs-popover-header-color: inherit;
+ --bs-popover-header-bg: var(--bs-secondary-bg);
--bs-popover-body-padding-x: 1rem;
--bs-popover-body-padding-y: 1rem;
- --bs-popover-body-color: #212529;
+ --bs-popover-body-color: var(--bs-body-color);
--bs-popover-arrow-width: 1rem;
--bs-popover-arrow-height: 0.5rem;
--bs-popover-arrow-border: var(--bs-popover-border-color);
@@ -5890,7 +6083,7 @@ textarea.form-control-lg {
}
@media (prefers-reduced-motion: reduce) {
.carousel-fade .active.carousel-item-start,
-.carousel-fade .active.carousel-item-end {
+ .carousel-fade .active.carousel-item-end {
transition: none;
}
}
@@ -5915,7 +6108,7 @@ textarea.form-control-lg {
}
@media (prefers-reduced-motion: reduce) {
.carousel-control-prev,
-.carousel-control-next {
+ .carousel-control-next {
transition: none;
}
}
@@ -5974,7 +6167,6 @@ textarea.form-control-lg {
margin-right: 15%;
margin-bottom: 1rem;
margin-left: 15%;
- list-style: none;
}
.carousel-indicators [data-bs-target] {
box-sizing: content-box;
@@ -6025,6 +6217,18 @@ textarea.form-control-lg {
color: #000;
}
+[data-bs-theme=dark] .carousel .carousel-control-prev-icon,
+[data-bs-theme=dark] .carousel .carousel-control-next-icon, [data-bs-theme=dark].carousel .carousel-control-prev-icon,
+[data-bs-theme=dark].carousel .carousel-control-next-icon {
+ filter: invert(1) grayscale(100);
+}
+[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target], [data-bs-theme=dark].carousel .carousel-indicators [data-bs-target] {
+ background-color: #000;
+}
+[data-bs-theme=dark] .carousel .carousel-caption, [data-bs-theme=dark].carousel .carousel-caption {
+ color: #000;
+}
+
.spinner-grow,
.spinner-border {
display: inline-block;
@@ -6083,7 +6287,7 @@ textarea.form-control-lg {
@media (prefers-reduced-motion: reduce) {
.spinner-border,
-.spinner-grow {
+ .spinner-grow {
--bs-spinner-animation-speed: 1.5s;
}
}
@@ -6093,11 +6297,13 @@ textarea.form-control-lg {
--bs-offcanvas-height: 30vh;
--bs-offcanvas-padding-x: 1rem;
--bs-offcanvas-padding-y: 1rem;
- --bs-offcanvas-color: ;
- --bs-offcanvas-bg: #fff;
- --bs-offcanvas-border-width: 1px;
+ --bs-offcanvas-color: var(--bs-body-color);
+ --bs-offcanvas-bg: var(--bs-body-bg);
+ --bs-offcanvas-border-width: var(--bs-border-width);
--bs-offcanvas-border-color: var(--bs-border-color-translucent);
--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+ --bs-offcanvas-transition: transform 0.3s ease-in-out;
+ --bs-offcanvas-title-line-height: 1.5;
}
@media (max-width: 575.98px) {
@@ -6113,7 +6319,7 @@ textarea.form-control-lg {
background-color: var(--bs-offcanvas-bg);
background-clip: padding-box;
outline: 0;
- transition: transform 0.3s ease-in-out;
+ transition: var(--bs-offcanvas-transition);
}
}
@media (max-width: 575.98px) and (prefers-reduced-motion: reduce) {
@@ -6129,8 +6335,6 @@ textarea.form-control-lg {
border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(-100%);
}
-}
-@media (max-width: 575.98px) {
.offcanvas-sm.offcanvas-end {
top: 0;
right: 0;
@@ -6138,8 +6342,6 @@ textarea.form-control-lg {
border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(100%);
}
-}
-@media (max-width: 575.98px) {
.offcanvas-sm.offcanvas-top {
top: 0;
right: 0;
@@ -6149,8 +6351,6 @@ textarea.form-control-lg {
border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(-100%);
}
-}
-@media (max-width: 575.98px) {
.offcanvas-sm.offcanvas-bottom {
right: 0;
left: 0;
@@ -6159,13 +6359,9 @@ textarea.form-control-lg {
border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(100%);
}
-}
-@media (max-width: 575.98px) {
.offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) {
transform: none;
}
-}
-@media (max-width: 575.98px) {
.offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show {
visibility: visible;
}
@@ -6201,7 +6397,7 @@ textarea.form-control-lg {
background-color: var(--bs-offcanvas-bg);
background-clip: padding-box;
outline: 0;
- transition: transform 0.3s ease-in-out;
+ transition: var(--bs-offcanvas-transition);
}
}
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
@@ -6217,8 +6413,6 @@ textarea.form-control-lg {
border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(-100%);
}
-}
-@media (max-width: 767.98px) {
.offcanvas-md.offcanvas-end {
top: 0;
right: 0;
@@ -6226,8 +6420,6 @@ textarea.form-control-lg {
border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(100%);
}
-}
-@media (max-width: 767.98px) {
.offcanvas-md.offcanvas-top {
top: 0;
right: 0;
@@ -6237,8 +6429,6 @@ textarea.form-control-lg {
border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(-100%);
}
-}
-@media (max-width: 767.98px) {
.offcanvas-md.offcanvas-bottom {
right: 0;
left: 0;
@@ -6247,13 +6437,9 @@ textarea.form-control-lg {
border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(100%);
}
-}
-@media (max-width: 767.98px) {
.offcanvas-md.showing, .offcanvas-md.show:not(.hiding) {
transform: none;
}
-}
-@media (max-width: 767.98px) {
.offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show {
visibility: visible;
}
@@ -6289,7 +6475,7 @@ textarea.form-control-lg {
background-color: var(--bs-offcanvas-bg);
background-clip: padding-box;
outline: 0;
- transition: transform 0.3s ease-in-out;
+ transition: var(--bs-offcanvas-transition);
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
@@ -6305,8 +6491,6 @@ textarea.form-control-lg {
border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(-100%);
}
-}
-@media (max-width: 991.98px) {
.offcanvas-lg.offcanvas-end {
top: 0;
right: 0;
@@ -6314,8 +6498,6 @@ textarea.form-control-lg {
border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(100%);
}
-}
-@media (max-width: 991.98px) {
.offcanvas-lg.offcanvas-top {
top: 0;
right: 0;
@@ -6325,8 +6507,6 @@ textarea.form-control-lg {
border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(-100%);
}
-}
-@media (max-width: 991.98px) {
.offcanvas-lg.offcanvas-bottom {
right: 0;
left: 0;
@@ -6335,13 +6515,9 @@ textarea.form-control-lg {
border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(100%);
}
-}
-@media (max-width: 991.98px) {
.offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) {
transform: none;
}
-}
-@media (max-width: 991.98px) {
.offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show {
visibility: visible;
}
@@ -6377,7 +6553,7 @@ textarea.form-control-lg {
background-color: var(--bs-offcanvas-bg);
background-clip: padding-box;
outline: 0;
- transition: transform 0.3s ease-in-out;
+ transition: var(--bs-offcanvas-transition);
}
}
@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) {
@@ -6393,8 +6569,6 @@ textarea.form-control-lg {
border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(-100%);
}
-}
-@media (max-width: 1199.98px) {
.offcanvas-xl.offcanvas-end {
top: 0;
right: 0;
@@ -6402,8 +6576,6 @@ textarea.form-control-lg {
border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(100%);
}
-}
-@media (max-width: 1199.98px) {
.offcanvas-xl.offcanvas-top {
top: 0;
right: 0;
@@ -6413,8 +6585,6 @@ textarea.form-control-lg {
border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(-100%);
}
-}
-@media (max-width: 1199.98px) {
.offcanvas-xl.offcanvas-bottom {
right: 0;
left: 0;
@@ -6423,13 +6593,9 @@ textarea.form-control-lg {
border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(100%);
}
-}
-@media (max-width: 1199.98px) {
.offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) {
transform: none;
}
-}
-@media (max-width: 1199.98px) {
.offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show {
visibility: visible;
}
@@ -6465,7 +6631,7 @@ textarea.form-control-lg {
background-color: var(--bs-offcanvas-bg);
background-clip: padding-box;
outline: 0;
- transition: transform 0.3s ease-in-out;
+ transition: var(--bs-offcanvas-transition);
}
}
@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce) {
@@ -6481,8 +6647,6 @@ textarea.form-control-lg {
border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(-100%);
}
-}
-@media (max-width: 1399.98px) {
.offcanvas-xxl.offcanvas-end {
top: 0;
right: 0;
@@ -6490,8 +6654,6 @@ textarea.form-control-lg {
border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateX(100%);
}
-}
-@media (max-width: 1399.98px) {
.offcanvas-xxl.offcanvas-top {
top: 0;
right: 0;
@@ -6501,8 +6663,6 @@ textarea.form-control-lg {
border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(-100%);
}
-}
-@media (max-width: 1399.98px) {
.offcanvas-xxl.offcanvas-bottom {
right: 0;
left: 0;
@@ -6511,13 +6671,9 @@ textarea.form-control-lg {
border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
transform: translateY(100%);
}
-}
-@media (max-width: 1399.98px) {
.offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) {
transform: none;
}
-}
-@media (max-width: 1399.98px) {
.offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show {
visibility: visible;
}
@@ -6552,7 +6708,7 @@ textarea.form-control-lg {
background-color: var(--bs-offcanvas-bg);
background-clip: padding-box;
outline: 0;
- transition: transform 0.3s ease-in-out;
+ transition: var(--bs-offcanvas-transition);
}
@media (prefers-reduced-motion: reduce) {
.offcanvas {
@@ -6628,7 +6784,7 @@ textarea.form-control-lg {
.offcanvas-title {
margin-bottom: 0;
- line-height: 1.5;
+ line-height: var(--bs-offcanvas-title-line-height);
}
.offcanvas-body {
@@ -6693,98 +6849,173 @@ textarea.form-control-lg {
.text-bg-primary {
color: #fff !important;
- background-color: RGBA(13, 110, 253, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important;
}
.text-bg-secondary {
color: #fff !important;
- background-color: RGBA(108, 117, 125, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important;
}
.text-bg-success {
color: #fff !important;
- background-color: RGBA(25, 135, 84, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important;
}
.text-bg-info {
color: #000 !important;
- background-color: RGBA(13, 202, 240, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important;
}
.text-bg-warning {
color: #000 !important;
- background-color: RGBA(255, 193, 7, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important;
}
.text-bg-danger {
color: #fff !important;
- background-color: RGBA(220, 53, 69, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important;
}
.text-bg-light {
color: #000 !important;
- background-color: RGBA(248, 249, 250, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important;
}
.text-bg-dark {
color: #fff !important;
- background-color: RGBA(33, 37, 41, var(--bs-bg-opacity, 1)) !important;
+ background-color: RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important;
}
.link-primary {
- color: #0d6efd !important;
+ color: RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-primary:hover, .link-primary:focus {
- color: #0a58ca !important;
+ color: RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important;
}
.link-secondary {
- color: #6c757d !important;
+ color: RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-secondary:hover, .link-secondary:focus {
- color: #565e64 !important;
+ color: RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important;
}
.link-success {
- color: #198754 !important;
+ color: RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-success:hover, .link-success:focus {
- color: #146c43 !important;
+ color: RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important;
}
.link-info {
- color: #0dcaf0 !important;
+ color: RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-info:hover, .link-info:focus {
- color: #3dd5f3 !important;
+ color: RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important;
}
.link-warning {
- color: #ffc107 !important;
+ color: RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-warning:hover, .link-warning:focus {
- color: #ffcd39 !important;
+ color: RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important;
}
.link-danger {
- color: #dc3545 !important;
+ color: RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-danger:hover, .link-danger:focus {
- color: #b02a37 !important;
+ color: RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important;
}
.link-light {
- color: #f8f9fa !important;
+ color: RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-light:hover, .link-light:focus {
- color: #f9fafb !important;
+ color: RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important;
}
.link-dark {
- color: #212529 !important;
+ color: RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-dark:hover, .link-dark:focus {
- color: #1a1e21 !important;
+ color: RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-body-emphasis {
+ color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important;
+}
+.link-body-emphasis:hover, .link-body-emphasis:focus {
+ color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important;
+ text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important;
+}
+
+.focus-ring:focus {
+ outline: 0;
+ box-shadow: var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color);
+}
+
+.icon-link {
+ display: inline-flex;
+ gap: 0.375rem;
+ align-items: center;
+ -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));
+ text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));
+ text-underline-offset: 0.25em;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+}
+.icon-link > .bi {
+ flex-shrink: 0;
+ width: 1em;
+ height: 1em;
+ fill: currentcolor;
+ transition: 0.2s ease-in-out transform;
+}
+@media (prefers-reduced-motion: reduce) {
+ .icon-link > .bi {
+ transition: none;
+ }
+}
+
+.icon-link-hover:hover > .bi, .icon-link-hover:focus-visible > .bi {
+ transform: var(--bs-icon-link-transform, translate3d(0.25em, 0, 0));
}
.ratio {
@@ -6936,7 +7167,6 @@ textarea.form-control-lg {
.visually-hidden,
.visually-hidden-focusable:not(:focus):not(:focus-within) {
- position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
@@ -6946,6 +7176,10 @@ textarea.form-control-lg {
white-space: nowrap !important;
border: 0 !important;
}
+.visually-hidden:not(caption),
+.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) {
+ position: absolute !important;
+}
.stretched-link::after {
position: absolute;
@@ -6966,7 +7200,7 @@ textarea.form-control-lg {
.vr {
display: inline-block;
align-self: stretch;
- width: 1px;
+ width: var(--bs-border-width);
min-height: 1em;
background-color: currentcolor;
opacity: 0.25;
@@ -7008,6 +7242,31 @@ textarea.form-control-lg {
float: none !important;
}
+.object-fit-contain {
+ -o-object-fit: contain !important;
+ object-fit: contain !important;
+}
+
+.object-fit-cover {
+ -o-object-fit: cover !important;
+ object-fit: cover !important;
+}
+
+.object-fit-fill {
+ -o-object-fit: fill !important;
+ object-fit: fill !important;
+}
+
+.object-fit-scale {
+ -o-object-fit: scale-down !important;
+ object-fit: scale-down !important;
+}
+
+.object-fit-none {
+ -o-object-fit: none !important;
+ object-fit: none !important;
+}
+
.opacity-0 {
opacity: 0 !important;
}
@@ -7044,6 +7303,38 @@ textarea.form-control-lg {
overflow: scroll !important;
}
+.overflow-x-auto {
+ overflow-x: auto !important;
+}
+
+.overflow-x-hidden {
+ overflow-x: hidden !important;
+}
+
+.overflow-x-visible {
+ overflow-x: visible !important;
+}
+
+.overflow-x-scroll {
+ overflow-x: scroll !important;
+}
+
+.overflow-y-auto {
+ overflow-y: auto !important;
+}
+
+.overflow-y-hidden {
+ overflow-y: hidden !important;
+}
+
+.overflow-y-visible {
+ overflow-y: visible !important;
+}
+
+.overflow-y-scroll {
+ overflow-y: scroll !important;
+}
+
.d-inline {
display: inline !important;
}
@@ -7060,6 +7351,10 @@ textarea.form-control-lg {
display: grid !important;
}
+.d-inline-grid {
+ display: inline-grid !important;
+}
+
.d-table {
display: table !important;
}
@@ -7100,6 +7395,38 @@ textarea.form-control-lg {
box-shadow: none !important;
}
+.focus-ring-primary {
+ --bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity));
+}
+
+.focus-ring-secondary {
+ --bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity));
+}
+
+.focus-ring-success {
+ --bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity));
+}
+
+.focus-ring-info {
+ --bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity));
+}
+
+.focus-ring-warning {
+ --bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity));
+}
+
+.focus-ring-danger {
+ --bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity));
+}
+
+.focus-ring-light {
+ --bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity));
+}
+
+.focus-ring-dark {
+ --bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity));
+}
+
.position-static {
position: static !important;
}
@@ -7261,29 +7588,66 @@ textarea.form-control-lg {
border-color: rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important;
}
+.border-black {
+ --bs-border-opacity: 1;
+ border-color: rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important;
+}
+
.border-white {
--bs-border-opacity: 1;
border-color: rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important;
}
+.border-primary-subtle {
+ border-color: var(--bs-primary-border-subtle) !important;
+}
+
+.border-secondary-subtle {
+ border-color: var(--bs-secondary-border-subtle) !important;
+}
+
+.border-success-subtle {
+ border-color: var(--bs-success-border-subtle) !important;
+}
+
+.border-info-subtle {
+ border-color: var(--bs-info-border-subtle) !important;
+}
+
+.border-warning-subtle {
+ border-color: var(--bs-warning-border-subtle) !important;
+}
+
+.border-danger-subtle {
+ border-color: var(--bs-danger-border-subtle) !important;
+}
+
+.border-light-subtle {
+ border-color: var(--bs-light-border-subtle) !important;
+}
+
+.border-dark-subtle {
+ border-color: var(--bs-dark-border-subtle) !important;
+}
+
.border-1 {
- --bs-border-width: 1px;
+ border-width: 1px !important;
}
.border-2 {
- --bs-border-width: 2px;
+ border-width: 2px !important;
}
.border-3 {
- --bs-border-width: 3px;
+ border-width: 3px !important;
}
.border-4 {
- --bs-border-width: 4px;
+ border-width: 4px !important;
}
.border-5 {
- --bs-border-width: 5px;
+ border-width: 5px !important;
}
.border-opacity-10 {
@@ -7956,6 +8320,60 @@ textarea.form-control-lg {
gap: 3rem !important;
}
+.row-gap-0 {
+ row-gap: 0 !important;
+}
+
+.row-gap-1 {
+ row-gap: 0.25rem !important;
+}
+
+.row-gap-2 {
+ row-gap: 0.5rem !important;
+}
+
+.row-gap-3 {
+ row-gap: 1rem !important;
+}
+
+.row-gap-4 {
+ row-gap: 1.5rem !important;
+}
+
+.row-gap-5 {
+ row-gap: 3rem !important;
+}
+
+.column-gap-0 {
+ -moz-column-gap: 0 !important;
+ column-gap: 0 !important;
+}
+
+.column-gap-1 {
+ -moz-column-gap: 0.25rem !important;
+ column-gap: 0.25rem !important;
+}
+
+.column-gap-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.5rem !important;
+}
+
+.column-gap-3 {
+ -moz-column-gap: 1rem !important;
+ column-gap: 1rem !important;
+}
+
+.column-gap-4 {
+ -moz-column-gap: 1.5rem !important;
+ column-gap: 1.5rem !important;
+}
+
+.column-gap-5 {
+ -moz-column-gap: 3rem !important;
+ column-gap: 3rem !important;
+}
+
.font-monospace {
font-family: var(--bs-font-monospace) !important;
}
@@ -7992,26 +8410,30 @@ textarea.form-control-lg {
font-style: normal !important;
}
-.fw-light {
- font-weight: 300 !important;
-}
-
.fw-lighter {
font-weight: lighter !important;
}
+.fw-light {
+ font-weight: 300 !important;
+}
+
.fw-normal {
font-weight: 400 !important;
}
-.fw-bold {
- font-weight: 700 !important;
+.fw-medium {
+ font-weight: 500 !important;
}
.fw-semibold {
font-weight: 600 !important;
}
+.fw-bold {
+ font-weight: 700 !important;
+}
+
.fw-bolder {
font-weight: bolder !important;
}
@@ -8140,7 +8562,7 @@ textarea.form-control-lg {
.text-muted {
--bs-text-opacity: 1;
- color: #6c757d !important;
+ color: var(--bs-secondary-color) !important;
}
.text-black-50 {
@@ -8153,6 +8575,21 @@ textarea.form-control-lg {
color: rgba(255, 255, 255, 0.5) !important;
}
+.text-body-secondary {
+ --bs-text-opacity: 1;
+ color: var(--bs-secondary-color) !important;
+}
+
+.text-body-tertiary {
+ --bs-text-opacity: 1;
+ color: var(--bs-tertiary-color) !important;
+}
+
+.text-body-emphasis {
+ --bs-text-opacity: 1;
+ color: var(--bs-emphasis-color) !important;
+}
+
.text-reset {
--bs-text-opacity: 1;
color: inherit !important;
@@ -8174,6 +8611,204 @@ textarea.form-control-lg {
--bs-text-opacity: 1;
}
+.text-primary-emphasis {
+ color: var(--bs-primary-text-emphasis) !important;
+}
+
+.text-secondary-emphasis {
+ color: var(--bs-secondary-text-emphasis) !important;
+}
+
+.text-success-emphasis {
+ color: var(--bs-success-text-emphasis) !important;
+}
+
+.text-info-emphasis {
+ color: var(--bs-info-text-emphasis) !important;
+}
+
+.text-warning-emphasis {
+ color: var(--bs-warning-text-emphasis) !important;
+}
+
+.text-danger-emphasis {
+ color: var(--bs-danger-text-emphasis) !important;
+}
+
+.text-light-emphasis {
+ color: var(--bs-light-text-emphasis) !important;
+}
+
+.text-dark-emphasis {
+ color: var(--bs-dark-text-emphasis) !important;
+}
+
+.link-opacity-10 {
+ --bs-link-opacity: 0.1;
+}
+
+.link-opacity-10-hover:hover {
+ --bs-link-opacity: 0.1;
+}
+
+.link-opacity-25 {
+ --bs-link-opacity: 0.25;
+}
+
+.link-opacity-25-hover:hover {
+ --bs-link-opacity: 0.25;
+}
+
+.link-opacity-50 {
+ --bs-link-opacity: 0.5;
+}
+
+.link-opacity-50-hover:hover {
+ --bs-link-opacity: 0.5;
+}
+
+.link-opacity-75 {
+ --bs-link-opacity: 0.75;
+}
+
+.link-opacity-75-hover:hover {
+ --bs-link-opacity: 0.75;
+}
+
+.link-opacity-100 {
+ --bs-link-opacity: 1;
+}
+
+.link-opacity-100-hover:hover {
+ --bs-link-opacity: 1;
+}
+
+.link-offset-1 {
+ text-underline-offset: 0.125em !important;
+}
+
+.link-offset-1-hover:hover {
+ text-underline-offset: 0.125em !important;
+}
+
+.link-offset-2 {
+ text-underline-offset: 0.25em !important;
+}
+
+.link-offset-2-hover:hover {
+ text-underline-offset: 0.25em !important;
+}
+
+.link-offset-3 {
+ text-underline-offset: 0.375em !important;
+}
+
+.link-offset-3-hover:hover {
+ text-underline-offset: 0.375em !important;
+}
+
+.link-underline-primary {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-secondary {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-success {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-info {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-warning {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-danger {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-light {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-dark {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-underline-opacity-0 {
+ --bs-link-underline-opacity: 0;
+}
+
+.link-underline-opacity-0-hover:hover {
+ --bs-link-underline-opacity: 0;
+}
+
+.link-underline-opacity-10 {
+ --bs-link-underline-opacity: 0.1;
+}
+
+.link-underline-opacity-10-hover:hover {
+ --bs-link-underline-opacity: 0.1;
+}
+
+.link-underline-opacity-25 {
+ --bs-link-underline-opacity: 0.25;
+}
+
+.link-underline-opacity-25-hover:hover {
+ --bs-link-underline-opacity: 0.25;
+}
+
+.link-underline-opacity-50 {
+ --bs-link-underline-opacity: 0.5;
+}
+
+.link-underline-opacity-50-hover:hover {
+ --bs-link-underline-opacity: 0.5;
+}
+
+.link-underline-opacity-75 {
+ --bs-link-underline-opacity: 0.75;
+}
+
+.link-underline-opacity-75-hover:hover {
+ --bs-link-underline-opacity: 0.75;
+}
+
+.link-underline-opacity-100 {
+ --bs-link-underline-opacity: 1;
+}
+
+.link-underline-opacity-100-hover:hover {
+ --bs-link-underline-opacity: 1;
+}
+
.bg-primary {
--bs-bg-opacity: 1;
background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important;
@@ -8234,6 +8869,16 @@ textarea.form-control-lg {
background-color: transparent !important;
}
+.bg-body-secondary {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-body-tertiary {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important;
+}
+
.bg-opacity-10 {
--bs-bg-opacity: 0.1;
}
@@ -8254,6 +8899,38 @@ textarea.form-control-lg {
--bs-bg-opacity: 1;
}
+.bg-primary-subtle {
+ background-color: var(--bs-primary-bg-subtle) !important;
+}
+
+.bg-secondary-subtle {
+ background-color: var(--bs-secondary-bg-subtle) !important;
+}
+
+.bg-success-subtle {
+ background-color: var(--bs-success-bg-subtle) !important;
+}
+
+.bg-info-subtle {
+ background-color: var(--bs-info-bg-subtle) !important;
+}
+
+.bg-warning-subtle {
+ background-color: var(--bs-warning-bg-subtle) !important;
+}
+
+.bg-danger-subtle {
+ background-color: var(--bs-danger-bg-subtle) !important;
+}
+
+.bg-light-subtle {
+ background-color: var(--bs-light-bg-subtle) !important;
+}
+
+.bg-dark-subtle {
+ background-color: var(--bs-dark-bg-subtle) !important;
+}
+
.bg-gradient {
background-image: var(--bs-gradient) !important;
}
@@ -8309,7 +8986,7 @@ textarea.form-control-lg {
}
.rounded-5 {
- border-radius: var(--bs-border-radius-2xl) !important;
+ border-radius: var(--bs-border-radius-xxl) !important;
}
.rounded-circle {
@@ -8325,21 +9002,181 @@ textarea.form-control-lg {
border-top-right-radius: var(--bs-border-radius) !important;
}
+.rounded-top-0 {
+ border-top-left-radius: 0 !important;
+ border-top-right-radius: 0 !important;
+}
+
+.rounded-top-1 {
+ border-top-left-radius: var(--bs-border-radius-sm) !important;
+ border-top-right-radius: var(--bs-border-radius-sm) !important;
+}
+
+.rounded-top-2 {
+ border-top-left-radius: var(--bs-border-radius) !important;
+ border-top-right-radius: var(--bs-border-radius) !important;
+}
+
+.rounded-top-3 {
+ border-top-left-radius: var(--bs-border-radius-lg) !important;
+ border-top-right-radius: var(--bs-border-radius-lg) !important;
+}
+
+.rounded-top-4 {
+ border-top-left-radius: var(--bs-border-radius-xl) !important;
+ border-top-right-radius: var(--bs-border-radius-xl) !important;
+}
+
+.rounded-top-5 {
+ border-top-left-radius: var(--bs-border-radius-xxl) !important;
+ border-top-right-radius: var(--bs-border-radius-xxl) !important;
+}
+
+.rounded-top-circle {
+ border-top-left-radius: 50% !important;
+ border-top-right-radius: 50% !important;
+}
+
+.rounded-top-pill {
+ border-top-left-radius: var(--bs-border-radius-pill) !important;
+ border-top-right-radius: var(--bs-border-radius-pill) !important;
+}
+
.rounded-end {
border-top-right-radius: var(--bs-border-radius) !important;
border-bottom-right-radius: var(--bs-border-radius) !important;
}
+.rounded-end-0 {
+ border-top-right-radius: 0 !important;
+ border-bottom-right-radius: 0 !important;
+}
+
+.rounded-end-1 {
+ border-top-right-radius: var(--bs-border-radius-sm) !important;
+ border-bottom-right-radius: var(--bs-border-radius-sm) !important;
+}
+
+.rounded-end-2 {
+ border-top-right-radius: var(--bs-border-radius) !important;
+ border-bottom-right-radius: var(--bs-border-radius) !important;
+}
+
+.rounded-end-3 {
+ border-top-right-radius: var(--bs-border-radius-lg) !important;
+ border-bottom-right-radius: var(--bs-border-radius-lg) !important;
+}
+
+.rounded-end-4 {
+ border-top-right-radius: var(--bs-border-radius-xl) !important;
+ border-bottom-right-radius: var(--bs-border-radius-xl) !important;
+}
+
+.rounded-end-5 {
+ border-top-right-radius: var(--bs-border-radius-xxl) !important;
+ border-bottom-right-radius: var(--bs-border-radius-xxl) !important;
+}
+
+.rounded-end-circle {
+ border-top-right-radius: 50% !important;
+ border-bottom-right-radius: 50% !important;
+}
+
+.rounded-end-pill {
+ border-top-right-radius: var(--bs-border-radius-pill) !important;
+ border-bottom-right-radius: var(--bs-border-radius-pill) !important;
+}
+
.rounded-bottom {
border-bottom-right-radius: var(--bs-border-radius) !important;
border-bottom-left-radius: var(--bs-border-radius) !important;
}
+.rounded-bottom-0 {
+ border-bottom-right-radius: 0 !important;
+ border-bottom-left-radius: 0 !important;
+}
+
+.rounded-bottom-1 {
+ border-bottom-right-radius: var(--bs-border-radius-sm) !important;
+ border-bottom-left-radius: var(--bs-border-radius-sm) !important;
+}
+
+.rounded-bottom-2 {
+ border-bottom-right-radius: var(--bs-border-radius) !important;
+ border-bottom-left-radius: var(--bs-border-radius) !important;
+}
+
+.rounded-bottom-3 {
+ border-bottom-right-radius: var(--bs-border-radius-lg) !important;
+ border-bottom-left-radius: var(--bs-border-radius-lg) !important;
+}
+
+.rounded-bottom-4 {
+ border-bottom-right-radius: var(--bs-border-radius-xl) !important;
+ border-bottom-left-radius: var(--bs-border-radius-xl) !important;
+}
+
+.rounded-bottom-5 {
+ border-bottom-right-radius: var(--bs-border-radius-xxl) !important;
+ border-bottom-left-radius: var(--bs-border-radius-xxl) !important;
+}
+
+.rounded-bottom-circle {
+ border-bottom-right-radius: 50% !important;
+ border-bottom-left-radius: 50% !important;
+}
+
+.rounded-bottom-pill {
+ border-bottom-right-radius: var(--bs-border-radius-pill) !important;
+ border-bottom-left-radius: var(--bs-border-radius-pill) !important;
+}
+
.rounded-start {
border-bottom-left-radius: var(--bs-border-radius) !important;
border-top-left-radius: var(--bs-border-radius) !important;
}
+.rounded-start-0 {
+ border-bottom-left-radius: 0 !important;
+ border-top-left-radius: 0 !important;
+}
+
+.rounded-start-1 {
+ border-bottom-left-radius: var(--bs-border-radius-sm) !important;
+ border-top-left-radius: var(--bs-border-radius-sm) !important;
+}
+
+.rounded-start-2 {
+ border-bottom-left-radius: var(--bs-border-radius) !important;
+ border-top-left-radius: var(--bs-border-radius) !important;
+}
+
+.rounded-start-3 {
+ border-bottom-left-radius: var(--bs-border-radius-lg) !important;
+ border-top-left-radius: var(--bs-border-radius-lg) !important;
+}
+
+.rounded-start-4 {
+ border-bottom-left-radius: var(--bs-border-radius-xl) !important;
+ border-top-left-radius: var(--bs-border-radius-xl) !important;
+}
+
+.rounded-start-5 {
+ border-bottom-left-radius: var(--bs-border-radius-xxl) !important;
+ border-top-left-radius: var(--bs-border-radius-xxl) !important;
+}
+
+.rounded-start-circle {
+ border-bottom-left-radius: 50% !important;
+ border-top-left-radius: 50% !important;
+}
+
+.rounded-start-pill {
+ border-bottom-left-radius: var(--bs-border-radius-pill) !important;
+ border-top-left-radius: var(--bs-border-radius-pill) !important;
+}
+
.visible {
visibility: visible !important;
}
@@ -8348,6 +9185,26 @@ textarea.form-control-lg {
visibility: hidden !important;
}
+.z-n1 {
+ z-index: -1 !important;
+}
+
+.z-0 {
+ z-index: 0 !important;
+}
+
+.z-1 {
+ z-index: 1 !important;
+}
+
+.z-2 {
+ z-index: 2 !important;
+}
+
+.z-3 {
+ z-index: 3 !important;
+}
+
@media (min-width: 576px) {
.float-sm-start {
float: left !important;
@@ -8358,6 +9215,26 @@ textarea.form-control-lg {
.float-sm-none {
float: none !important;
}
+ .object-fit-sm-contain {
+ -o-object-fit: contain !important;
+ object-fit: contain !important;
+ }
+ .object-fit-sm-cover {
+ -o-object-fit: cover !important;
+ object-fit: cover !important;
+ }
+ .object-fit-sm-fill {
+ -o-object-fit: fill !important;
+ object-fit: fill !important;
+ }
+ .object-fit-sm-scale {
+ -o-object-fit: scale-down !important;
+ object-fit: scale-down !important;
+ }
+ .object-fit-sm-none {
+ -o-object-fit: none !important;
+ object-fit: none !important;
+ }
.d-sm-inline {
display: inline !important;
}
@@ -8370,6 +9247,9 @@ textarea.form-control-lg {
.d-sm-grid {
display: grid !important;
}
+ .d-sm-inline-grid {
+ display: inline-grid !important;
+ }
.d-sm-table {
display: table !important;
}
@@ -8834,6 +9714,48 @@ textarea.form-control-lg {
.gap-sm-5 {
gap: 3rem !important;
}
+ .row-gap-sm-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-sm-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-sm-2 {
+ row-gap: 0.5rem !important;
+ }
+ .row-gap-sm-3 {
+ row-gap: 1rem !important;
+ }
+ .row-gap-sm-4 {
+ row-gap: 1.5rem !important;
+ }
+ .row-gap-sm-5 {
+ row-gap: 3rem !important;
+ }
+ .column-gap-sm-0 {
+ -moz-column-gap: 0 !important;
+ column-gap: 0 !important;
+ }
+ .column-gap-sm-1 {
+ -moz-column-gap: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-sm-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.5rem !important;
+ }
+ .column-gap-sm-3 {
+ -moz-column-gap: 1rem !important;
+ column-gap: 1rem !important;
+ }
+ .column-gap-sm-4 {
+ -moz-column-gap: 1.5rem !important;
+ column-gap: 1.5rem !important;
+ }
+ .column-gap-sm-5 {
+ -moz-column-gap: 3rem !important;
+ column-gap: 3rem !important;
+ }
.text-sm-start {
text-align: left !important;
}
@@ -8854,6 +9776,26 @@ textarea.form-control-lg {
.float-md-none {
float: none !important;
}
+ .object-fit-md-contain {
+ -o-object-fit: contain !important;
+ object-fit: contain !important;
+ }
+ .object-fit-md-cover {
+ -o-object-fit: cover !important;
+ object-fit: cover !important;
+ }
+ .object-fit-md-fill {
+ -o-object-fit: fill !important;
+ object-fit: fill !important;
+ }
+ .object-fit-md-scale {
+ -o-object-fit: scale-down !important;
+ object-fit: scale-down !important;
+ }
+ .object-fit-md-none {
+ -o-object-fit: none !important;
+ object-fit: none !important;
+ }
.d-md-inline {
display: inline !important;
}
@@ -8866,6 +9808,9 @@ textarea.form-control-lg {
.d-md-grid {
display: grid !important;
}
+ .d-md-inline-grid {
+ display: inline-grid !important;
+ }
.d-md-table {
display: table !important;
}
@@ -9330,6 +10275,48 @@ textarea.form-control-lg {
.gap-md-5 {
gap: 3rem !important;
}
+ .row-gap-md-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-md-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-md-2 {
+ row-gap: 0.5rem !important;
+ }
+ .row-gap-md-3 {
+ row-gap: 1rem !important;
+ }
+ .row-gap-md-4 {
+ row-gap: 1.5rem !important;
+ }
+ .row-gap-md-5 {
+ row-gap: 3rem !important;
+ }
+ .column-gap-md-0 {
+ -moz-column-gap: 0 !important;
+ column-gap: 0 !important;
+ }
+ .column-gap-md-1 {
+ -moz-column-gap: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-md-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.5rem !important;
+ }
+ .column-gap-md-3 {
+ -moz-column-gap: 1rem !important;
+ column-gap: 1rem !important;
+ }
+ .column-gap-md-4 {
+ -moz-column-gap: 1.5rem !important;
+ column-gap: 1.5rem !important;
+ }
+ .column-gap-md-5 {
+ -moz-column-gap: 3rem !important;
+ column-gap: 3rem !important;
+ }
.text-md-start {
text-align: left !important;
}
@@ -9350,6 +10337,26 @@ textarea.form-control-lg {
.float-lg-none {
float: none !important;
}
+ .object-fit-lg-contain {
+ -o-object-fit: contain !important;
+ object-fit: contain !important;
+ }
+ .object-fit-lg-cover {
+ -o-object-fit: cover !important;
+ object-fit: cover !important;
+ }
+ .object-fit-lg-fill {
+ -o-object-fit: fill !important;
+ object-fit: fill !important;
+ }
+ .object-fit-lg-scale {
+ -o-object-fit: scale-down !important;
+ object-fit: scale-down !important;
+ }
+ .object-fit-lg-none {
+ -o-object-fit: none !important;
+ object-fit: none !important;
+ }
.d-lg-inline {
display: inline !important;
}
@@ -9362,6 +10369,9 @@ textarea.form-control-lg {
.d-lg-grid {
display: grid !important;
}
+ .d-lg-inline-grid {
+ display: inline-grid !important;
+ }
.d-lg-table {
display: table !important;
}
@@ -9826,6 +10836,48 @@ textarea.form-control-lg {
.gap-lg-5 {
gap: 3rem !important;
}
+ .row-gap-lg-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-lg-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-lg-2 {
+ row-gap: 0.5rem !important;
+ }
+ .row-gap-lg-3 {
+ row-gap: 1rem !important;
+ }
+ .row-gap-lg-4 {
+ row-gap: 1.5rem !important;
+ }
+ .row-gap-lg-5 {
+ row-gap: 3rem !important;
+ }
+ .column-gap-lg-0 {
+ -moz-column-gap: 0 !important;
+ column-gap: 0 !important;
+ }
+ .column-gap-lg-1 {
+ -moz-column-gap: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-lg-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.5rem !important;
+ }
+ .column-gap-lg-3 {
+ -moz-column-gap: 1rem !important;
+ column-gap: 1rem !important;
+ }
+ .column-gap-lg-4 {
+ -moz-column-gap: 1.5rem !important;
+ column-gap: 1.5rem !important;
+ }
+ .column-gap-lg-5 {
+ -moz-column-gap: 3rem !important;
+ column-gap: 3rem !important;
+ }
.text-lg-start {
text-align: left !important;
}
@@ -9846,6 +10898,26 @@ textarea.form-control-lg {
.float-xl-none {
float: none !important;
}
+ .object-fit-xl-contain {
+ -o-object-fit: contain !important;
+ object-fit: contain !important;
+ }
+ .object-fit-xl-cover {
+ -o-object-fit: cover !important;
+ object-fit: cover !important;
+ }
+ .object-fit-xl-fill {
+ -o-object-fit: fill !important;
+ object-fit: fill !important;
+ }
+ .object-fit-xl-scale {
+ -o-object-fit: scale-down !important;
+ object-fit: scale-down !important;
+ }
+ .object-fit-xl-none {
+ -o-object-fit: none !important;
+ object-fit: none !important;
+ }
.d-xl-inline {
display: inline !important;
}
@@ -9858,6 +10930,9 @@ textarea.form-control-lg {
.d-xl-grid {
display: grid !important;
}
+ .d-xl-inline-grid {
+ display: inline-grid !important;
+ }
.d-xl-table {
display: table !important;
}
@@ -10322,6 +11397,48 @@ textarea.form-control-lg {
.gap-xl-5 {
gap: 3rem !important;
}
+ .row-gap-xl-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-xl-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-xl-2 {
+ row-gap: 0.5rem !important;
+ }
+ .row-gap-xl-3 {
+ row-gap: 1rem !important;
+ }
+ .row-gap-xl-4 {
+ row-gap: 1.5rem !important;
+ }
+ .row-gap-xl-5 {
+ row-gap: 3rem !important;
+ }
+ .column-gap-xl-0 {
+ -moz-column-gap: 0 !important;
+ column-gap: 0 !important;
+ }
+ .column-gap-xl-1 {
+ -moz-column-gap: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-xl-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.5rem !important;
+ }
+ .column-gap-xl-3 {
+ -moz-column-gap: 1rem !important;
+ column-gap: 1rem !important;
+ }
+ .column-gap-xl-4 {
+ -moz-column-gap: 1.5rem !important;
+ column-gap: 1.5rem !important;
+ }
+ .column-gap-xl-5 {
+ -moz-column-gap: 3rem !important;
+ column-gap: 3rem !important;
+ }
.text-xl-start {
text-align: left !important;
}
@@ -10342,6 +11459,26 @@ textarea.form-control-lg {
.float-xxl-none {
float: none !important;
}
+ .object-fit-xxl-contain {
+ -o-object-fit: contain !important;
+ object-fit: contain !important;
+ }
+ .object-fit-xxl-cover {
+ -o-object-fit: cover !important;
+ object-fit: cover !important;
+ }
+ .object-fit-xxl-fill {
+ -o-object-fit: fill !important;
+ object-fit: fill !important;
+ }
+ .object-fit-xxl-scale {
+ -o-object-fit: scale-down !important;
+ object-fit: scale-down !important;
+ }
+ .object-fit-xxl-none {
+ -o-object-fit: none !important;
+ object-fit: none !important;
+ }
.d-xxl-inline {
display: inline !important;
}
@@ -10354,6 +11491,9 @@ textarea.form-control-lg {
.d-xxl-grid {
display: grid !important;
}
+ .d-xxl-inline-grid {
+ display: inline-grid !important;
+ }
.d-xxl-table {
display: table !important;
}
@@ -10818,6 +11958,48 @@ textarea.form-control-lg {
.gap-xxl-5 {
gap: 3rem !important;
}
+ .row-gap-xxl-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-xxl-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-xxl-2 {
+ row-gap: 0.5rem !important;
+ }
+ .row-gap-xxl-3 {
+ row-gap: 1rem !important;
+ }
+ .row-gap-xxl-4 {
+ row-gap: 1.5rem !important;
+ }
+ .row-gap-xxl-5 {
+ row-gap: 3rem !important;
+ }
+ .column-gap-xxl-0 {
+ -moz-column-gap: 0 !important;
+ column-gap: 0 !important;
+ }
+ .column-gap-xxl-1 {
+ -moz-column-gap: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-xxl-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.5rem !important;
+ }
+ .column-gap-xxl-3 {
+ -moz-column-gap: 1rem !important;
+ column-gap: 1rem !important;
+ }
+ .column-gap-xxl-4 {
+ -moz-column-gap: 1.5rem !important;
+ column-gap: 1.5rem !important;
+ }
+ .column-gap-xxl-5 {
+ -moz-column-gap: 3rem !important;
+ column-gap: 3rem !important;
+ }
.text-xxl-start {
text-align: left !important;
}
@@ -10855,6 +12037,9 @@ textarea.form-control-lg {
.d-print-grid {
display: grid !important;
}
+ .d-print-inline-grid {
+ display: inline-grid !important;
+ }
.d-print-table {
display: table !important;
}
diff --git a/src/static/scripts/datatables.css b/src/static/scripts/datatables.css
index 0dd6669c..e3205479 100644
--- a/src/static/scripts/datatables.css
+++ b/src/static/scripts/datatables.css
@@ -4,10 +4,10 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
- * https://datatables.net/download/#bs5/dt-1.13.4
+ * https://datatables.net/download/#bs5/dt-1.13.6
*
* Included libraries:
- * DataTables 1.13.4
+ * DataTables 1.13.6
*/
@charset "UTF-8";
@@ -15,6 +15,13 @@
--dt-row-selected: 13, 110, 253;
--dt-row-selected-text: 255, 255, 255;
--dt-row-selected-link: 9, 10, 11;
+ --dt-row-stripe: 0, 0, 0;
+ --dt-row-hover: 0, 0, 0;
+ --dt-column-ordering: 0, 0, 0;
+ --dt-html-background: white;
+}
+:root.dark {
+ --dt-html-background: rgb(33, 37, 41);
}
table.dataTable td.dt-control {
@@ -22,25 +29,19 @@ table.dataTable td.dt-control {
cursor: pointer;
}
table.dataTable td.dt-control:before {
- height: 1em;
- width: 1em;
- margin-top: -9px;
display: inline-block;
- color: white;
- border: 0.15em solid white;
- border-radius: 1em;
- box-shadow: 0 0 0.2em #444;
- box-sizing: content-box;
- text-align: center;
- text-indent: 0 !important;
- font-family: "Courier New", Courier, monospace;
- line-height: 1em;
- content: "+";
- background-color: #31b131;
+ color: rgba(0, 0, 0, 0.5);
+ content: "►";
}
table.dataTable tr.dt-hasChild td.dt-control:before {
- content: "-";
- background-color: #d33333;
+ content: "▼";
+}
+
+html.dark table.dataTable td.dt-control:before {
+ color: rgba(255, 255, 255, 0.5);
+}
+html.dark table.dataTable tr.dt-hasChild td.dt-control:before {
+ color: rgba(255, 255, 255, 0.5);
}
table.dataTable thead > tr > th.sorting, table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting_asc_disabled, table.dataTable thead > tr > th.sorting_desc_disabled,
@@ -303,14 +304,14 @@ table.dataTable > tbody > tr.selected a {
color: rgb(var(--dt-row-selected-link));
}
table.dataTable.table-striped > tbody > tr.odd > * {
- box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.05);
}
table.dataTable.table-striped > tbody > tr.odd.selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.95);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.95);
}
table.dataTable.table-hover > tbody > tr:hover > * {
- box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.075);
}
table.dataTable.table-hover > tbody > tr.selected:hover > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.975);
@@ -441,4 +442,10 @@ div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:last-
padding-right: 0;
}
+:root[data-bs-theme=dark] {
+ --dt-row-hover: 255, 255, 255;
+ --dt-row-stripe: 255, 255, 255;
+ --dt-column-ordering: 255, 255, 255;
+}
+
diff --git a/src/static/scripts/datatables.js b/src/static/scripts/datatables.js
index 520de77c..735ba65e 100644
--- a/src/static/scripts/datatables.js
+++ b/src/static/scripts/datatables.js
@@ -4,20 +4,20 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
- * https://datatables.net/download/#bs5/dt-1.13.4
+ * https://datatables.net/download/#bs5/dt-1.13.6
*
* Included libraries:
- * DataTables 1.13.4
+ * DataTables 1.13.6
*/
-/*! DataTables 1.13.4
+/*! DataTables 1.13.6
* ©2008-2023 SpryMedia Ltd - datatables.net/license
*/
/**
* @summary DataTables
* @description Paginate, search and order HTML tables
- * @version 1.13.4
+ * @version 1.13.6
* @author SpryMedia Ltd
* @contact www.datatables.net
* @copyright SpryMedia Ltd.
@@ -50,7 +50,7 @@
// returns a factory function that expects the window object
var jq = require('jquery');
- if (typeof window !== 'undefined') {
+ if (typeof window === 'undefined') {
module.exports = function (root, $) {
if ( ! root ) {
// CommonJS environments without a window global must pass a
@@ -1396,7 +1396,7 @@
var _isNumber = function ( d, decimalPoint, formatted ) {
- let type = typeof d;
+ var type = typeof d;
var strType = type === 'string';
if ( type === 'number' || type === 'bigint') {
@@ -1530,7 +1530,9 @@
var _stripHtml = function ( d ) {
- return d.replace( _re_html, '' );
+ return d
+ .replace( _re_html, '' ) // Complete tags
+ .replace(/<script/i, ''); // Safety for incomplete script tag
};
@@ -1904,7 +1906,10 @@
continue;
}
- if ( data === null || data[ a[i] ] === undefined ) {
+ if (data === null || data[ a[i] ] === null) {
+ return null;
+ }
+ else if ( data === undefined || data[ a[i] ] === undefined ) {
return undefined;
}
@@ -2351,6 +2356,12 @@
oCol.aDataSort = [ oOptions.iDataSort ];
}
_fnMap( oCol, oOptions, "aDataSort" );
+
+ // Fall back to the aria-label attribute on the table header if no ariaTitle is
+ // provided.
+ if (! oCol.ariaTitle) {
+ oCol.ariaTitle = th.attr("aria-label");
+ }
}
/* Cache the data get and set functions for speed */
@@ -4075,11 +4086,16 @@
settings.iDraw++;
_fnProcessingDisplay( settings, true );
+ // Keep track of drawHold state to handle scrolling after the Ajax call
+ var drawHold = settings._drawHold;
+
_fnBuildAjax(
settings,
_fnAjaxParameters( settings ),
function(json) {
+ settings._drawHold = drawHold;
_fnAjaxUpdateDraw( settings, json );
+ settings._drawHold = false;
}
);
}
@@ -4343,7 +4359,7 @@
_fnThrottle( searchFn, searchDelay ) :
searchFn
)
- .on( 'mouseup', function(e) {
+ .on( 'mouseup.DT', function(e) {
// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
// checks the value to see if it has changed. In other browsers it won't have.
@@ -4409,7 +4425,7 @@
if ( _fnDataSource( oSettings ) != 'ssp' )
{
/* Global filter */
- _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive, oInput.return );
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
fnSaveFilter( oInput );
/* Now do the individual column filter */
@@ -4578,11 +4594,15 @@
*
* ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
*/
- var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
+ var a = $.map( search.match( /["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''], function ( word ) {
if ( word.charAt(0) === '"' ) {
var m = word.match( /^"(.*)"$/ );
word = m ? m[1] : word;
}
+ else if ( word.charAt(0) === '\u201C' ) {
+ var m = word.match( /^\u201C(.*)\u201D$/ );
+ word = m ? m[1] : word;
+ }
return word.replace('"', '');
} );
@@ -9386,7 +9406,8 @@
* Set the jQuery or window object to be used by DataTables
*
* @param {*} module Library / container object
- * @param {string} type Library or container type `lib` or `win`.
+ * @param {string} [type] Library or container type `lib`, `win` or `datetime`.
+ * If not provided, automatic detection is attempted.
*/
DataTable.use = function (module, type) {
if (type === 'lib' || module.fn) {
@@ -9396,6 +9417,9 @@
window = module;
document = module.document;
}
+ else if (type === 'datetime' || module.type === 'DateTime') {
+ DataTable.DateTime = module;
+ }
}
/**
@@ -9755,7 +9779,9 @@
resolved._;
}
- return resolved.replace( '%d', plural ); // nb: plural might be undefined,
+ return typeof resolved === 'string'
+ ? resolved.replace( '%d', plural ) // nb: plural might be undefined,
+ : resolved;
} );
/**
* Version string for plug-ins to check compatibility. Allowed format is
@@ -9765,7 +9791,7 @@
* @type string
* @default Version number
*/
- DataTable.version = "1.13.4";
+ DataTable.version = "1.13.6";
/**
* Private data store, containing all of the settings objects that are
@@ -14189,7 +14215,7 @@
*
* @type string
*/
- build:"bs5/dt-1.13.4",
+ build:"bs5/dt-1.13.6",
/**
@@ -14830,7 +14856,7 @@
var btnDisplay, btnClass;
var attach = function( container, buttons ) {
- var i, ien, node, button, tabIndex;
+ var i, ien, node, button;
var disabledClass = classes.sPageButtonDisabled;
var clickHandler = function ( e ) {
_fnPageChange( settings, e.data.action, true );
@@ -14845,9 +14871,10 @@
attach( inner, button );
}
else {
+ var disabled = false;
+
btnDisplay = null;
btnClass = button;
- tabIndex = settings.iTabIndex;
switch ( button ) {
case 'ellipsis':
@@ -14858,8 +14885,7 @@
btnDisplay = lang.sFirst;
if ( page === 0 ) {
- tabIndex = -1;
- btnClass += ' ' + disabledClass;
+ disabled = true;
}
break;
@@ -14867,8 +14893,7 @@
btnDisplay = lang.sPrevious;
if ( page === 0 ) {
- tabIndex = -1;
- btnClass += ' ' + disabledClass;
+ disabled = true;
}
break;
@@ -14876,8 +14901,7 @@
btnDisplay = lang.sNext;
if ( pages === 0 || page === pages-1 ) {
- tabIndex = -1;
- btnClass += ' ' + disabledClass;
+ disabled = true;
}
break;
@@ -14885,8 +14909,7 @@
btnDisplay = lang.sLast;
if ( pages === 0 || page === pages-1 ) {
- tabIndex = -1;
- btnClass += ' ' + disabledClass;
+ disabled = true;
}
break;
@@ -14899,18 +14922,20 @@
if ( btnDisplay !== null ) {
var tag = settings.oInit.pagingTag || 'a';
- var disabled = btnClass.indexOf(disabledClass) !== -1;
-
+
+ if (disabled) {
+ btnClass += ' ' + disabledClass;
+ }
node = $('<'+tag+'>', {
'class': classes.sPageButton+' '+btnClass,
'aria-controls': settings.sTableId,
'aria-disabled': disabled ? 'true' : null,
'aria-label': aria[ button ],
- 'aria-role': 'link',
+ 'role': 'link',
'aria-current': btnClass === classes.sPageButtonActive ? 'page' : null,
'data-dt-idx': button,
- 'tabindex': tabIndex,
+ 'tabindex': disabled ? -1 : settings.iTabIndex,
'id': idx === 0 && typeof button === 'string' ?
settings.sTableId +'_'+ button :
null
@@ -15041,7 +15066,7 @@
return -Infinity;
}
- let type = typeof d;
+ var type = typeof d;
if (type === 'number' || type === 'bigint') {
return d;
@@ -15415,7 +15440,7 @@
var __thousands = ',';
var __decimal = '.';
- if (Intl) {
+ if (window.Intl !== undefined) {
try {
var num = new Intl.NumberFormat().formatToParts(100000.1);
@@ -15718,7 +15743,7 @@
}
};
- if (typeof window !== 'undefined') {
+ if (typeof window === 'undefined') {
module.exports = function (root, $) {
if ( ! root ) {
// CommonJS environments without a window global must pass a
@@ -15856,10 +15881,10 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
'aria-controls': settings.sTableId,
'aria-disabled': disabled ? 'true' : null,
'aria-label': aria[ button ],
- 'aria-role': 'link',
+ 'role': 'link',
'aria-current': btnClass === 'active' ? 'page' : null,
'data-dt-idx': button,
- 'tabindex': settings.iTabIndex,
+ 'tabindex': disabled ? -1 : settings.iTabIndex,
'class': 'page-link'
} )
.html( btnDisplay )
diff --git a/src/static/scripts/jquery-3.6.4.slim.js b/src/static/scripts/jquery-3.7.0.slim.js
index edf6ce9c..15a1a291 100644
--- a/src/static/scripts/jquery-3.6.4.slim.js
+++ b/src/static/scripts/jquery-3.7.0.slim.js
@@ -1,15 +1,12 @@
/*!
- * jQuery JavaScript Library v3.6.4 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween
+ * jQuery JavaScript Library v3.7.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween
* https://jquery.com/
*
- * Includes Sizzle.js
- * https://sizzlejs.com/
- *
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
- * Date: 2023-03-08T15:29Z
+ * Date: 2023-05-11T18:29Z
*/
( function( global, factory ) {
@@ -150,8 +147,9 @@ function toType( obj ) {
-var
- version = "3.6.4 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween",
+var version = "3.7.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween",
+
+ rhtmlSuffix = /HTML$/i,
// Define a local copy of jQuery
jQuery = function( selector, context ) {
@@ -397,6 +395,33 @@ jQuery.extend( {
return obj;
},
+
+ // Retrieve the text value of an array of DOM nodes
+ text: function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+
+ // If no nodeType, this is expected to be an array
+ while ( ( node = elem[ i++ ] ) ) {
+
+ // Do not traverse comment nodes
+ ret += jQuery.text( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ return elem.textContent;
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+ },
+
// results is for internal usage only
makeArray: function( arr, results ) {
var ret = results || [];
@@ -419,6 +444,15 @@ jQuery.extend( {
return arr == null ? -1 : indexOf.call( arr, elem, i );
},
+ isXMLDoc: function( elem ) {
+ var namespace = elem && elem.namespaceURI,
+ docElem = elem && ( elem.ownerDocument || elem ).documentElement;
+
+ // Assume HTML when documentElement doesn't yet exist, such as inside
+ // document fragments.
+ return !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || "HTML" );
+ },
+
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
merge: function( first, second ) {
@@ -520,43 +554,98 @@ function isArrayLike( obj ) {
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
-var Sizzle =
-/*!
- * Sizzle CSS Selector Engine v2.3.10
- * https://sizzlejs.com/
- *
- * Copyright JS Foundation and other contributors
- * Released under the MIT license
- * https://js.foundation/
- *
- * Date: 2023-02-14
- */
-( function( window ) {
+
+
+function nodeName( elem, name ) {
+
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+
+}
+var pop = arr.pop;
+
+
+var sort = arr.sort;
+
+
+var splice = arr.splice;
+
+
+var whitespace = "[\\x20\\t\\r\\n\\f]";
+
+
+var rtrimCSS = new RegExp(
+ "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$",
+ "g"
+);
+
+
+
+
+// Note: an element does not contain itself
+jQuery.contains = function( a, b ) {
+ var bup = b && b.parentNode;
+
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+
+ // Support: IE 9 - 11+
+ // IE doesn't have `contains` on SVG.
+ a.contains ?
+ a.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ) );
+};
+
+
+
+
+// CSS string/identifier serialization
+// https://drafts.csswg.org/cssom/#common-serializing-idioms
+var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
+
+function fcssescape( ch, asCodePoint ) {
+ if ( asCodePoint ) {
+
+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
+ if ( ch === "\0" ) {
+ return "\uFFFD";
+ }
+
+ // Control characters and (dependent upon position) numbers get escaped as code points
+ return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+ }
+
+ // Other potentially-special ASCII characters get backslash-escaped
+ return "\\" + ch;
+}
+
+jQuery.escapeSelector = function( sel ) {
+ return ( sel + "" ).replace( rcssescape, fcssescape );
+};
+
+
+
+
+var preferredDoc = document,
+ pushNative = push;
+
+( function() {
+
var i,
- support,
Expr,
- getText,
- isXML,
- tokenize,
- compile,
- select,
outermostContext,
sortInput,
hasDuplicate,
+ push = pushNative,
// Local document vars
- setDocument,
document,
- docElem,
+ documentElement,
documentIsHTML,
rbuggyQSA,
- rbuggyMatches,
matches,
- contains,
// Instance-specific data
- expando = "sizzle" + 1 * new Date(),
- preferredDoc = window.document,
+ expando = jQuery.expando,
dirruns = 0,
done = 0,
classCache = createCache(),
@@ -570,47 +659,22 @@ var i,
return 0;
},
- // Instance methods
- hasOwn = ( {} ).hasOwnProperty,
- arr = [],
- pop = arr.pop,
- pushNative = arr.push,
- push = arr.push,
- slice = arr.slice,
-
- // Use a stripped-down indexOf as it's faster than native
- // https://jsperf.com/thor-indexof-vs-for/5
- indexOf = function( list, elem ) {
- var i = 0,
- len = list.length;
- for ( ; i < len; i++ ) {
- if ( list[ i ] === elem ) {
- return i;
- }
- }
- return -1;
- },
-
- booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" +
- "ismap|loop|multiple|open|readonly|required|scoped",
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" +
+ "loop|multiple|open|readonly|required|scoped",
// Regular expressions
- // http://www.w3.org/TR/css3-selectors/#whitespace
- whitespace = "[\\x20\\t\\r\\n\\f]",
-
// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",
- // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors
attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
// Operator (capture 2)
"*([*^$|!~]?=)" + whitespace +
- // "Attribute values must be CSS identifiers [capture 5]
- // or strings [capture 3 or capture 4]"
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
whitespace + "*\\]",
@@ -629,101 +693,88 @@ var i,
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
rwhitespace = new RegExp( whitespace + "+", "g" ),
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" +
- whitespace + "+$", "g" ),
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace +
- "*" ),
+ rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" +
+ whitespace + "*" ),
rdescend = new RegExp( whitespace + "|>" ),
rpseudo = new RegExp( pseudos ),
ridentifier = new RegExp( "^" + identifier + "$" ),
matchExpr = {
- "ID": new RegExp( "^#(" + identifier + ")" ),
- "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
- "TAG": new RegExp( "^(" + identifier + "|[*])" ),
- "ATTR": new RegExp( "^" + attributes ),
- "PSEUDO": new RegExp( "^" + pseudos ),
- "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
- whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
- whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
- "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ ID: new RegExp( "^#(" + identifier + ")" ),
+ CLASS: new RegExp( "^\\.(" + identifier + ")" ),
+ TAG: new RegExp( "^(" + identifier + "|[*])" ),
+ ATTR: new RegExp( "^" + attributes ),
+ PSEUDO: new RegExp( "^" + pseudos ),
+ CHILD: new RegExp(
+ "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
+ whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
+ whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ bool: new RegExp( "^(?:" + booleans + ")$", "i" ),
// For use in libraries implementing .is()
// We use this for POS matching in `select`
- "needsContext": new RegExp( "^" + whitespace +
+ needsContext: new RegExp( "^" + whitespace +
"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
"*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
},
- rhtml = /HTML$/i,
rinputs = /^(?:input|select|textarea|button)$/i,
rheader = /^h\d$/i,
- rnative = /^[^{]+\{\s*\[native \w/,
-
// Easily-parseable/retrievable ID or TAG or CLASS selectors
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
rsibling = /[+~]/,
// CSS escapes
- // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
- runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ),
+ // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace +
+ "?|\\\\([^\\r\\n\\f])", "g" ),
funescape = function( escape, nonHex ) {
var high = "0x" + escape.slice( 1 ) - 0x10000;
- return nonHex ?
+ if ( nonHex ) {
// Strip the backslash prefix from a non-hex escape sequence
- nonHex :
-
- // Replace a hexadecimal escape sequence with the encoded Unicode code point
- // Support: IE <=11+
- // For values outside the Basic Multilingual Plane (BMP), manually construct a
- // surrogate pair
- high < 0 ?
- String.fromCharCode( high + 0x10000 ) :
- String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- },
-
- // CSS string/identifier serialization
- // https://drafts.csswg.org/cssom/#common-serializing-idioms
- rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
- fcssescape = function( ch, asCodePoint ) {
- if ( asCodePoint ) {
-
- // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
- if ( ch === "\0" ) {
- return "\uFFFD";
- }
-
- // Control characters and (dependent upon position) numbers get escaped as code points
- return ch.slice( 0, -1 ) + "\\" +
- ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+ return nonHex;
}
- // Other potentially-special ASCII characters get backslash-escaped
- return "\\" + ch;
+ // Replace a hexadecimal escape sequence with the encoded Unicode code point
+ // Support: IE <=11+
+ // For values outside the Basic Multilingual Plane (BMP), manually construct a
+ // surrogate pair
+ return high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
},
- // Used for iframes
- // See setDocument()
+ // Used for iframes; see `setDocument`.
+ // Support: IE 9 - 11+, Edge 12 - 18+
// Removing the function wrapper causes a "Permission Denied"
- // error in IE
+ // error in IE/Edge.
unloadHandler = function() {
setDocument();
},
inDisabledFieldset = addCombinator(
function( elem ) {
- return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
+ return elem.disabled === true && nodeName( elem, "fieldset" );
},
{ dir: "parentNode", next: "legend" }
);
+// Support: IE <=9 only
+// Accessing document.activeElement can throw unexpectedly
+// https://bugs.jquery.com/ticket/13393
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
// Optimize for push.apply( _, NodeList )
try {
push.apply(
@@ -731,32 +782,22 @@ try {
preferredDoc.childNodes
);
- // Support: Android<4.0
+ // Support: Android <=4.0
// Detect silently failing push.apply
// eslint-disable-next-line no-unused-expressions
arr[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
- push = { apply: arr.length ?
-
- // Leverage slice if possible
- function( target, els ) {
+ push = {
+ apply: function( target, els ) {
pushNative.apply( target, slice.call( els ) );
- } :
-
- // Support: IE<9
- // Otherwise append directly
- function( target, els ) {
- var j = target.length,
- i = 0;
-
- // Can't trust NodeList.length
- while ( ( target[ j++ ] = els[ i++ ] ) ) {}
- target.length = j - 1;
+ },
+ call: function( target ) {
+ pushNative.apply( target, slice.call( arguments, 1 ) );
}
};
}
-function Sizzle( selector, context, results, seed ) {
+function find( selector, context, results, seed ) {
var m, i, elem, nid, match, groups, newSelector,
newContext = context && context.ownerDocument,
@@ -790,11 +831,10 @@ function Sizzle( selector, context, results, seed ) {
if ( nodeType === 9 ) {
if ( ( elem = context.getElementById( m ) ) ) {
- // Support: IE, Opera, Webkit
- // TODO: identify versions
+ // Support: IE 9 only
// getElementById can match elements by name instead of ID
if ( elem.id === m ) {
- results.push( elem );
+ push.call( results, elem );
return results;
}
} else {
@@ -804,14 +844,13 @@ function Sizzle( selector, context, results, seed ) {
// Element context
} else {
- // Support: IE, Opera, Webkit
- // TODO: identify versions
+ // Support: IE 9 only
// getElementById can match elements by name instead of ID
if ( newContext && ( elem = newContext.getElementById( m ) ) &&
- contains( context, elem ) &&
+ find.contains( context, elem ) &&
elem.id === m ) {
- results.push( elem );
+ push.call( results, elem );
return results;
}
}
@@ -822,22 +861,15 @@ function Sizzle( selector, context, results, seed ) {
return results;
// Class selector
- } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&
- context.getElementsByClassName ) {
-
+ } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) {
push.apply( results, context.getElementsByClassName( m ) );
return results;
}
}
// Take advantage of querySelectorAll
- if ( support.qsa &&
- !nonnativeSelectorCache[ selector + " " ] &&
- ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&
-
- // Support: IE 8 only
- // Exclude object elements
- ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) {
+ if ( !nonnativeSelectorCache[ selector + " " ] &&
+ ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) {
newSelector = selector;
newContext = context;
@@ -858,11 +890,15 @@ function Sizzle( selector, context, results, seed ) {
// We can use :scope instead of the ID hack if the browser
// supports it & if we're not changing the context.
- if ( newContext !== context || !support.scope ) {
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when
+ // strict-comparing two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( newContext != context || !support.scope ) {
// Capture the context ID, setting it first if necessary
if ( ( nid = context.getAttribute( "id" ) ) ) {
- nid = nid.replace( rcssescape, fcssescape );
+ nid = jQuery.escapeSelector( nid );
} else {
context.setAttribute( "id", ( nid = expando ) );
}
@@ -895,7 +931,7 @@ function Sizzle( selector, context, results, seed ) {
}
// All others
- return select( selector.replace( rtrim, "$1" ), context, results, seed );
+ return select( selector.replace( rtrimCSS, "$1" ), context, results, seed );
}
/**
@@ -909,7 +945,8 @@ function createCache() {
function cache( key, value ) {
- // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ // Use (key + " ") to avoid collision with native prototype properties
+ // (see https://github.com/jquery/sizzle/issues/157)
if ( keys.push( key + " " ) > Expr.cacheLength ) {
// Only keep the most recent entries
@@ -921,7 +958,7 @@ function createCache() {
}
/**
- * Mark a function for special use by Sizzle
+ * Mark a function for special use by jQuery selector module
* @param {Function} fn The function to mark
*/
function markFunction( fn ) {
@@ -953,55 +990,12 @@ function assert( fn ) {
}
/**
- * Adds the same handler for all of the specified attrs
- * @param {String} attrs Pipe-separated list of attributes
- * @param {Function} handler The method that will be applied
- */
-function addHandle( attrs, handler ) {
- var arr = attrs.split( "|" ),
- i = arr.length;
-
- while ( i-- ) {
- Expr.attrHandle[ arr[ i ] ] = handler;
- }
-}
-
-/**
- * Checks document order of two siblings
- * @param {Element} a
- * @param {Element} b
- * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
- */
-function siblingCheck( a, b ) {
- var cur = b && a,
- diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
- a.sourceIndex - b.sourceIndex;
-
- // Use IE sourceIndex if available on both nodes
- if ( diff ) {
- return diff;
- }
-
- // Check if b follows a
- if ( cur ) {
- while ( ( cur = cur.nextSibling ) ) {
- if ( cur === b ) {
- return -1;
- }
- }
- }
-
- return a ? 1 : -1;
-}
-
-/**
* Returns a function to use in pseudos for input types
* @param {String} type
*/
function createInputPseudo( type ) {
return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === type;
+ return nodeName( elem, "input" ) && elem.type === type;
};
}
@@ -1011,8 +1005,8 @@ function createInputPseudo( type ) {
*/
function createButtonPseudo( type ) {
return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return ( name === "input" || name === "button" ) && elem.type === type;
+ return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) &&
+ elem.type === type;
};
}
@@ -1048,14 +1042,13 @@ function createDisabledPseudo( disabled ) {
}
}
- // Support: IE 6 - 11
+ // Support: IE 6 - 11+
// Use the isDisabled shortcut property to check for disabled fieldset ancestors
return elem.isDisabled === disabled ||
// Where there is no isDisabled, check manually
- /* jshint -W018 */
elem.isDisabled !== !disabled &&
- inDisabledFieldset( elem ) === disabled;
+ inDisabledFieldset( elem ) === disabled;
}
return elem.disabled === disabled;
@@ -1095,7 +1088,7 @@ function createPositionalPseudo( fn ) {
}
/**
- * Checks a node for validity as a Sizzle context
+ * Checks a node for validity as a jQuery selector context
* @param {Element|Object=} context
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
*/
@@ -1103,31 +1096,13 @@ function testContext( context ) {
return context && typeof context.getElementsByTagName !== "undefined" && context;
}
-// Expose support vars for convenience
-support = Sizzle.support = {};
-
-/**
- * Detects XML nodes
- * @param {Element|Object} elem An element or a document
- * @returns {Boolean} True iff elem is a non-HTML XML node
- */
-isXML = Sizzle.isXML = function( elem ) {
- var namespace = elem && elem.namespaceURI,
- docElem = elem && ( elem.ownerDocument || elem ).documentElement;
-
- // Support: IE <=8
- // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
- // https://bugs.jquery.com/ticket/4833
- return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
-};
-
/**
* Sets document-related variables once based on the current document
- * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @param {Element|Object} [node] An element or document object to use to set the document
* @returns {Object} Returns the current document
*/
-setDocument = Sizzle.setDocument = function( node ) {
- var hasCompare, subWindow,
+function setDocument( node ) {
+ var subWindow,
doc = node ? node.ownerDocument || node : preferredDoc;
// Return early if doc is invalid or already selected
@@ -1141,11 +1116,17 @@ setDocument = Sizzle.setDocument = function( node ) {
// Update global variables
document = doc;
- docElem = document.documentElement;
- documentIsHTML = !isXML( document );
+ documentElement = document.documentElement;
+ documentIsHTML = !jQuery.isXMLDoc( document );
+
+ // Support: iOS 7 only, IE 9 - 11+
+ // Older browsers didn't support unprefixed `matches`.
+ matches = documentElement.matches ||
+ documentElement.webkitMatchesSelector ||
+ documentElement.msMatchesSelector;
// Support: IE 9 - 11+, Edge 12 - 18+
- // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+ // Accessing iframe documents after unload throws "permission denied" errors (see trac-13936)
// Support: IE 11+, Edge 17 - 18+
// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
// two documents; shallow comparisons work.
@@ -1153,29 +1134,35 @@ setDocument = Sizzle.setDocument = function( node ) {
if ( preferredDoc != document &&
( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
- // Support: IE 11, Edge
- if ( subWindow.addEventListener ) {
- subWindow.addEventListener( "unload", unloadHandler, false );
-
- // Support: IE 9 - 10 only
- } else if ( subWindow.attachEvent ) {
- subWindow.attachEvent( "onunload", unloadHandler );
- }
+ // Support: IE 9 - 11+, Edge 12 - 18+
+ subWindow.addEventListener( "unload", unloadHandler );
}
- // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,
- // Safari 4 - 5 only, Opera <=11.6 - 12.x only
- // IE/Edge & older browsers don't support the :scope pseudo-class.
- // Support: Safari 6.0 only
- // Safari 6.0 supports :scope but it's an alias of :root there.
- support.scope = assert( function( el ) {
- docElem.appendChild( el ).appendChild( document.createElement( "div" ) );
- return typeof el.querySelectorAll !== "undefined" &&
- !el.querySelectorAll( ":scope fieldset div" ).length;
+ // Support: IE <10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programmatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert( function( el ) {
+ documentElement.appendChild( el ).id = jQuery.expando;
+ return !document.getElementsByName ||
+ !document.getElementsByName( jQuery.expando ).length;
} );
- // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+
- // Make sure the the `:has()` argument is parsed unforgivingly.
+ // Support: IE 9 only
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node.
+ support.disconnectedMatch = assert( function( el ) {
+ return matches.call( el, "*" );
+ } );
+
+ // Support: IE 9 - 11+, Edge 12 - 18+
+ // IE/Edge don't support the :scope pseudo-class.
+ support.scope = assert( function() {
+ return document.querySelectorAll( ":scope" );
+ } );
+
+ // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only
+ // Make sure the `:has()` argument is parsed unforgivingly.
// We include `*` in the test to detect buggy implementations that are
// _selectively_ forgiving (specifically when the list includes at least
// one valid selector).
@@ -1192,54 +1179,22 @@ setDocument = Sizzle.setDocument = function( node ) {
}
} );
- /* Attributes
- ---------------------------------------------------------------------- */
-
- // Support: IE<8
- // Verify that getAttribute really returns attributes and not properties
- // (excepting IE8 booleans)
- support.attributes = assert( function( el ) {
- el.className = "i";
- return !el.getAttribute( "className" );
- } );
-
- /* getElement(s)By*
- ---------------------------------------------------------------------- */
-
- // Check if getElementsByTagName("*") returns only elements
- support.getElementsByTagName = assert( function( el ) {
- el.appendChild( document.createComment( "" ) );
- return !el.getElementsByTagName( "*" ).length;
- } );
-
- // Support: IE<9
- support.getElementsByClassName = rnative.test( document.getElementsByClassName );
-
- // Support: IE<10
- // Check if getElementById returns elements by name
- // The broken getElementById methods don't pick up programmatically-set names,
- // so use a roundabout getElementsByName test
- support.getById = assert( function( el ) {
- docElem.appendChild( el ).id = expando;
- return !document.getElementsByName || !document.getElementsByName( expando ).length;
- } );
-
// ID filter and find
if ( support.getById ) {
- Expr.filter[ "ID" ] = function( id ) {
+ Expr.filter.ID = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
return elem.getAttribute( "id" ) === attrId;
};
};
- Expr.find[ "ID" ] = function( id, context ) {
+ Expr.find.ID = function( id, context ) {
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var elem = context.getElementById( id );
return elem ? [ elem ] : [];
}
};
} else {
- Expr.filter[ "ID" ] = function( id ) {
+ Expr.filter.ID = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
var node = typeof elem.getAttributeNode !== "undefined" &&
@@ -1250,7 +1205,7 @@ setDocument = Sizzle.setDocument = function( node ) {
// Support: IE 6 - 7 only
// getElementById is not reliable as a find shortcut
- Expr.find[ "ID" ] = function( id, context ) {
+ Expr.find.ID = function( id, context ) {
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var node, i, elems,
elem = context.getElementById( id );
@@ -1280,40 +1235,18 @@ setDocument = Sizzle.setDocument = function( node ) {
}
// Tag
- Expr.find[ "TAG" ] = support.getElementsByTagName ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== "undefined" ) {
- return context.getElementsByTagName( tag );
-
- // DocumentFragment nodes don't have gEBTN
- } else if ( support.qsa ) {
- return context.querySelectorAll( tag );
- }
- } :
+ Expr.find.TAG = function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
- function( tag, context ) {
- var elem,
- tmp = [],
- i = 0,
-
- // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
- results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- while ( ( elem = results[ i++ ] ) ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- };
+ // DocumentFragment nodes don't have gEBTN
+ } else {
+ return context.querySelectorAll( tag );
+ }
+ };
// Class
- Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) {
+ Expr.find.CLASS = function( className, context ) {
if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
return context.getElementsByClassName( className );
}
@@ -1324,139 +1257,75 @@ setDocument = Sizzle.setDocument = function( node ) {
// QSA and matchesSelector support
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- rbuggyMatches = [];
-
- // qSa(:focus) reports false when true (Chrome 21)
- // We allow this because of a bug in IE8/9 that throws an error
- // whenever `document.activeElement` is accessed on an iframe
- // So, we allow :focus to pass through QSA all the time to avoid the IE error
- // See https://bugs.jquery.com/ticket/13378
rbuggyQSA = [];
- if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {
-
- // Build QSA regex
- // Regex strategy adopted from Diego Perini
- assert( function( el ) {
-
- var input;
-
- // Select is set to empty string on purpose
- // This is to test IE's treatment of not explicitly
- // setting a boolean content attribute,
- // since its presence should be enough
- // https://bugs.jquery.com/ticket/12359
- docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
- "<select id='" + expando + "-\r\\' msallowcapture=''>" +
- "<option selected=''></option></select>";
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert( function( el ) {
- // Support: IE8, Opera 11-12.16
- // Nothing should be selected when empty strings follow ^= or $= or *=
- // The test attribute must be unknown in Opera but "safe" for WinRT
- // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
- if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) {
- rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
- }
-
- // Support: IE8
- // Boolean attributes and "value" are not treated correctly
- if ( !el.querySelectorAll( "[selected]" ).length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
- }
+ var input;
- // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
- if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
- rbuggyQSA.push( "~=" );
- }
+ documentElement.appendChild( el ).innerHTML =
+ "<a id='" + expando + "' href='' disabled='disabled'></a>" +
+ "<select id='" + expando + "-\r\\' disabled='disabled'>" +
+ "<option selected=''></option></select>";
- // Support: IE 11+, Edge 15 - 18+
- // IE 11/Edge don't find elements on a `[name='']` query in some cases.
- // Adding a temporary attribute to the document before the selection works
- // around the issue.
- // Interestingly, IE 10 & older don't seem to have the issue.
- input = document.createElement( "input" );
- input.setAttribute( "name", "" );
- el.appendChild( input );
- if ( !el.querySelectorAll( "[name='']" ).length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
- whitespace + "*(?:''|\"\")" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here and will not see later tests
- if ( !el.querySelectorAll( ":checked" ).length ) {
- rbuggyQSA.push( ":checked" );
- }
-
- // Support: Safari 8+, iOS 8+
- // https://bugs.webkit.org/show_bug.cgi?id=136851
- // In-page `selector#id sibling-combinator selector` fails
- if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
- rbuggyQSA.push( ".#.+[+~]" );
- }
-
- // Support: Firefox <=3.6 - 5 only
- // Old Firefox doesn't throw on a badly-escaped identifier.
- el.querySelectorAll( "\\\f" );
- rbuggyQSA.push( "[\\r\\n\\f]" );
- } );
-
- assert( function( el ) {
- el.innerHTML = "<a href='' disabled='disabled'></a>" +
- "<select disabled='disabled'><option/></select>";
-
- // Support: Windows 8 Native Apps
- // The type and name attributes are restricted during .innerHTML assignment
- var input = document.createElement( "input" );
- input.setAttribute( "type", "hidden" );
- el.appendChild( input ).setAttribute( "name", "D" );
-
- // Support: IE8
- // Enforce case-sensitivity of name attribute
- if ( el.querySelectorAll( "[name=d]" ).length ) {
- rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
- }
-
- // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
- // IE8 throws error here and will not see later tests
- if ( el.querySelectorAll( ":enabled" ).length !== 2 ) {
- rbuggyQSA.push( ":enabled", ":disabled" );
- }
-
- // Support: IE9-11+
- // IE's :disabled selector does not pick up the children of disabled fieldsets
- docElem.appendChild( el ).disabled = true;
- if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
- rbuggyQSA.push( ":enabled", ":disabled" );
- }
-
- // Support: Opera 10 - 11 only
- // Opera 10-11 does not throw on post-comma invalid pseudos
- el.querySelectorAll( "*,:x" );
- rbuggyQSA.push( ",.*:" );
- } );
- }
+ // Support: iOS <=7 - 8 only
+ // Boolean attributes and "value" are not treated correctly in some XML documents
+ if ( !el.querySelectorAll( "[selected]" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
- if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||
- docElem.webkitMatchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.oMatchesSelector ||
- docElem.msMatchesSelector ) ) ) ) {
+ // Support: iOS <=7 - 8 only
+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push( "~=" );
+ }
- assert( function( el ) {
+ // Support: iOS 8 only
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibling-combinator selector` fails
+ if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push( ".#.+[+~]" );
+ }
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9)
- support.disconnectedMatch = matches.call( el, "*" );
+ // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+
+ // In some of the document kinds, these selectors wouldn't work natively.
+ // This is probably OK but for backwards compatibility we want to maintain
+ // handling them through jQuery traversal in jQuery 3.x.
+ if ( !el.querySelectorAll( ":checked" ).length ) {
+ rbuggyQSA.push( ":checked" );
+ }
- // This should fail with an exception
- // Gecko does not error, returns false instead
- matches.call( el, "[s!='']:x" );
- rbuggyMatches.push( "!=", pseudos );
- } );
- }
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ input = document.createElement( "input" );
+ input.setAttribute( "type", "hidden" );
+ el.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE 9 - 11+
+ // IE's :disabled selector does not pick up the children of disabled fieldsets
+ // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+
+ // In some of the document kinds, these selectors wouldn't work natively.
+ // This is probably OK but for backwards compatibility we want to maintain
+ // handling them through jQuery traversal in jQuery 3.x.
+ documentElement.appendChild( el ).disabled = true;
+ if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: IE 11+, Edge 15 - 18+
+ // IE 11/Edge don't find elements on a `[name='']` query in some cases.
+ // Adding a temporary attribute to the document before the selection works
+ // around the issue.
+ // Interestingly, IE 10 & older don't seem to have the issue.
+ input = document.createElement( "input" );
+ input.setAttribute( "name", "" );
+ el.appendChild( input );
+ if ( !el.querySelectorAll( "[name='']" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
+ whitespace + "*(?:''|\"\")" );
+ }
+ } );
if ( !support.cssHas ) {
@@ -1470,49 +1339,12 @@ setDocument = Sizzle.setDocument = function( node ) {
}
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
- rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
-
- /* Contains
- ---------------------------------------------------------------------- */
- hasCompare = rnative.test( docElem.compareDocumentPosition );
-
- // Element contains another
- // Purposefully self-exclusive
- // As in, an element does not contain itself
- contains = hasCompare || rnative.test( docElem.contains ) ?
- function( a, b ) {
-
- // Support: IE <9 only
- // IE doesn't have `contains` on `document` so we need to check for
- // `documentElement` presence.
- // We need to fall back to `a` when `documentElement` is missing
- // as `ownerDocument` of elements within `<template/>` may have
- // a null one - a default behavior of all modern browsers.
- var adown = a.nodeType === 9 && a.documentElement || a,
- bup = b && b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && (
- adown.contains ?
- adown.contains( bup ) :
- a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
- ) );
- } :
- function( a, b ) {
- if ( b ) {
- while ( ( b = b.parentNode ) ) {
- if ( b === a ) {
- return true;
- }
- }
- }
- return false;
- };
/* Sorting
---------------------------------------------------------------------- */
// Document order sorting
- sortOrder = hasCompare ?
- function( a, b ) {
+ sortOrder = function( a, b ) {
// Flag for duplicate removal
if ( a === b ) {
@@ -1546,8 +1378,8 @@ setDocument = Sizzle.setDocument = function( node ) {
// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
// two documents; shallow comparisons work.
// eslint-disable-next-line eqeqeq
- if ( a == document || a.ownerDocument == preferredDoc &&
- contains( preferredDoc, a ) ) {
+ if ( a === document || a.ownerDocument == preferredDoc &&
+ find.contains( preferredDoc, a ) ) {
return -1;
}
@@ -1555,100 +1387,33 @@ setDocument = Sizzle.setDocument = function( node ) {
// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
// two documents; shallow comparisons work.
// eslint-disable-next-line eqeqeq
- if ( b == document || b.ownerDocument == preferredDoc &&
- contains( preferredDoc, b ) ) {
+ if ( b === document || b.ownerDocument == preferredDoc &&
+ find.contains( preferredDoc, b ) ) {
return 1;
}
// Maintain original order
return sortInput ?
- ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
0;
}
return compare & 4 ? -1 : 1;
- } :
- function( a, b ) {
-
- // Exit early if the nodes are identical
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- var cur,
- i = 0,
- aup = a.parentNode,
- bup = b.parentNode,
- ap = [ a ],
- bp = [ b ];
-
- // Parentless nodes are either documents or disconnected
- if ( !aup || !bup ) {
-
- // Support: IE 11+, Edge 17 - 18+
- // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
- // two documents; shallow comparisons work.
- /* eslint-disable eqeqeq */
- return a == document ? -1 :
- b == document ? 1 :
- /* eslint-enable eqeqeq */
- aup ? -1 :
- bup ? 1 :
- sortInput ?
- ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
- 0;
-
- // If the nodes are siblings, we can do a quick check
- } else if ( aup === bup ) {
- return siblingCheck( a, b );
- }
-
- // Otherwise we need full lists of their ancestors for comparison
- cur = a;
- while ( ( cur = cur.parentNode ) ) {
- ap.unshift( cur );
- }
- cur = b;
- while ( ( cur = cur.parentNode ) ) {
- bp.unshift( cur );
- }
-
- // Walk down the tree looking for a discrepancy
- while ( ap[ i ] === bp[ i ] ) {
- i++;
- }
-
- return i ?
-
- // Do a sibling check if the nodes have a common ancestor
- siblingCheck( ap[ i ], bp[ i ] ) :
-
- // Otherwise nodes in our document sort first
- // Support: IE 11+, Edge 17 - 18+
- // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
- // two documents; shallow comparisons work.
- /* eslint-disable eqeqeq */
- ap[ i ] == preferredDoc ? -1 :
- bp[ i ] == preferredDoc ? 1 :
- /* eslint-enable eqeqeq */
- 0;
};
return document;
-};
+}
-Sizzle.matches = function( expr, elements ) {
- return Sizzle( expr, null, null, elements );
+find.matches = function( expr, elements ) {
+ return find( expr, null, null, elements );
};
-Sizzle.matchesSelector = function( elem, expr ) {
+find.matchesSelector = function( elem, expr ) {
setDocument( elem );
- if ( support.matchesSelector && documentIsHTML &&
+ if ( documentIsHTML &&
!nonnativeSelectorCache[ expr + " " ] &&
- ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
- ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
try {
var ret = matches.call( elem, expr );
@@ -1656,9 +1421,9 @@ Sizzle.matchesSelector = function( elem, expr ) {
// IE 9's matchesSelector returns false on disconnected nodes
if ( ret || support.disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9
- elem.document && elem.document.nodeType !== 11 ) {
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
return ret;
}
} catch ( e ) {
@@ -1666,10 +1431,10 @@ Sizzle.matchesSelector = function( elem, expr ) {
}
}
- return Sizzle( expr, document, null, [ elem ] ).length > 0;
+ return find( expr, document, null, [ elem ] ).length > 0;
};
-Sizzle.contains = function( context, elem ) {
+find.contains = function( context, elem ) {
// Set document vars if needed
// Support: IE 11+, Edge 17 - 18+
@@ -1679,10 +1444,11 @@ Sizzle.contains = function( context, elem ) {
if ( ( context.ownerDocument || context ) != document ) {
setDocument( context );
}
- return contains( context, elem );
+ return jQuery.contains( context, elem );
};
-Sizzle.attr = function( elem, name ) {
+
+find.attr = function( elem, name ) {
// Set document vars if needed
// Support: IE 11+, Edge 17 - 18+
@@ -1695,25 +1461,19 @@ Sizzle.attr = function( elem, name ) {
var fn = Expr.attrHandle[ name.toLowerCase() ],
- // Don't get fooled by Object.prototype properties (jQuery #13807)
+ // Don't get fooled by Object.prototype properties (see trac-13807)
val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
fn( elem, name, !documentIsHTML ) :
undefined;
- return val !== undefined ?
- val :
- support.attributes || !documentIsHTML ?
- elem.getAttribute( name ) :
- ( val = elem.getAttributeNode( name ) ) && val.specified ?
- val.value :
- null;
-};
+ if ( val !== undefined ) {
+ return val;
+ }
-Sizzle.escape = function( sel ) {
- return ( sel + "" ).replace( rcssescape, fcssescape );
+ return elem.getAttribute( name );
};
-Sizzle.error = function( msg ) {
+find.error = function( msg ) {
throw new Error( "Syntax error, unrecognized expression: " + msg );
};
@@ -1721,16 +1481,20 @@ Sizzle.error = function( msg ) {
* Document sorting and removing duplicates
* @param {ArrayLike} results
*/
-Sizzle.uniqueSort = function( results ) {
+jQuery.uniqueSort = function( results ) {
var elem,
duplicates = [],
j = 0,
i = 0;
// Unless we *know* we can detect duplicates, assume their presence
- hasDuplicate = !support.detectDuplicates;
- sortInput = !support.sortStable && results.slice( 0 );
- results.sort( sortOrder );
+ //
+ // Support: Android <=4.0+
+ // Testing for detecting duplicates is unpredictable so instead assume we can't
+ // depend on duplicate detection in all browsers without a stable sort.
+ hasDuplicate = !support.sortStable;
+ sortInput = !support.sortStable && slice.call( results, 0 );
+ sort.call( results, sortOrder );
if ( hasDuplicate ) {
while ( ( elem = results[ i++ ] ) ) {
@@ -1739,7 +1503,7 @@ Sizzle.uniqueSort = function( results ) {
}
}
while ( j-- ) {
- results.splice( duplicates[ j ], 1 );
+ splice.call( results, duplicates[ j ], 1 );
}
}
@@ -1750,47 +1514,11 @@ Sizzle.uniqueSort = function( results ) {
return results;
};
-/**
- * Utility function for retrieving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-getText = Sizzle.getText = function( elem ) {
- var node,
- ret = "",
- i = 0,
- nodeType = elem.nodeType;
-
- if ( !nodeType ) {
-
- // If no nodeType, this is expected to be an array
- while ( ( node = elem[ i++ ] ) ) {
-
- // Do not traverse comment nodes
- ret += getText( node );
- }
- } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
-
- // Use textContent for elements
- // innerText usage removed for consistency of new lines (jQuery #11153)
- if ( typeof elem.textContent === "string" ) {
- return elem.textContent;
- } else {
-
- // Traverse its children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- ret += getText( elem );
- }
- }
- } else if ( nodeType === 3 || nodeType === 4 ) {
- return elem.nodeValue;
- }
-
- // Do not include comment or processing instruction nodes
-
- return ret;
+jQuery.fn.uniqueSort = function() {
+ return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) );
};
-Expr = Sizzle.selectors = {
+Expr = jQuery.expr = {
// Can be adjusted by the user
cacheLength: 50,
@@ -1811,12 +1539,12 @@ Expr = Sizzle.selectors = {
},
preFilter: {
- "ATTR": function( match ) {
+ ATTR: function( match ) {
match[ 1 ] = match[ 1 ].replace( runescape, funescape );
// Move the given value to match[3] whether quoted or unquoted
- match[ 3 ] = ( match[ 3 ] || match[ 4 ] ||
- match[ 5 ] || "" ).replace( runescape, funescape );
+ match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" )
+ .replace( runescape, funescape );
if ( match[ 2 ] === "~=" ) {
match[ 3 ] = " " + match[ 3 ] + " ";
@@ -1825,7 +1553,7 @@ Expr = Sizzle.selectors = {
return match.slice( 0, 4 );
},
- "CHILD": function( match ) {
+ CHILD: function( match ) {
/* matches from matchExpr["CHILD"]
1 type (only|nth|...)
@@ -1843,29 +1571,30 @@ Expr = Sizzle.selectors = {
// nth-* requires argument
if ( !match[ 3 ] ) {
- Sizzle.error( match[ 0 ] );
+ find.error( match[ 0 ] );
}
// numeric x and y parameters for Expr.filter.CHILD
// remember that false/true cast respectively to 0/1
match[ 4 ] = +( match[ 4 ] ?
match[ 5 ] + ( match[ 6 ] || 1 ) :
- 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) );
+ 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" )
+ );
match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
- // other types prohibit arguments
+ // other types prohibit arguments
} else if ( match[ 3 ] ) {
- Sizzle.error( match[ 0 ] );
+ find.error( match[ 0 ] );
}
return match;
},
- "PSEUDO": function( match ) {
+ PSEUDO: function( match ) {
var excess,
unquoted = !match[ 6 ] && match[ 2 ];
- if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) {
+ if ( matchExpr.CHILD.test( match[ 0 ] ) ) {
return null;
}
@@ -1894,36 +1623,36 @@ Expr = Sizzle.selectors = {
filter: {
- "TAG": function( nodeNameSelector ) {
- var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ TAG: function( nodeNameSelector ) {
+ var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
return nodeNameSelector === "*" ?
function() {
return true;
} :
function( elem ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ return nodeName( elem, expectedNodeName );
};
},
- "CLASS": function( className ) {
+ CLASS: function( className ) {
var pattern = classCache[ className + " " ];
return pattern ||
- ( pattern = new RegExp( "(^|" + whitespace +
- ")" + className + "(" + whitespace + "|$)" ) ) && classCache(
- className, function( elem ) {
- return pattern.test(
- typeof elem.className === "string" && elem.className ||
- typeof elem.getAttribute !== "undefined" &&
- elem.getAttribute( "class" ) ||
- ""
- );
+ ( pattern = new RegExp( "(^|" + whitespace + ")" + className +
+ "(" + whitespace + "|$)" ) ) &&
+ classCache( className, function( elem ) {
+ return pattern.test(
+ typeof elem.className === "string" && elem.className ||
+ typeof elem.getAttribute !== "undefined" &&
+ elem.getAttribute( "class" ) ||
+ ""
+ );
} );
},
- "ATTR": function( name, operator, check ) {
+ ATTR: function( name, operator, check ) {
return function( elem ) {
- var result = Sizzle.attr( elem, name );
+ var result = find.attr( elem, name );
if ( result == null ) {
return operator === "!=";
@@ -1934,22 +1663,34 @@ Expr = Sizzle.selectors = {
result += "";
- /* eslint-disable max-len */
-
- return operator === "=" ? result === check :
- operator === "!=" ? result !== check :
- operator === "^=" ? check && result.indexOf( check ) === 0 :
- operator === "*=" ? check && result.indexOf( check ) > -1 :
- operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
- operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
- false;
- /* eslint-enable max-len */
+ if ( operator === "=" ) {
+ return result === check;
+ }
+ if ( operator === "!=" ) {
+ return result !== check;
+ }
+ if ( operator === "^=" ) {
+ return check && result.indexOf( check ) === 0;
+ }
+ if ( operator === "*=" ) {
+ return check && result.indexOf( check ) > -1;
+ }
+ if ( operator === "$=" ) {
+ return check && result.slice( -check.length ) === check;
+ }
+ if ( operator === "~=" ) {
+ return ( " " + result.replace( rwhitespace, " " ) + " " )
+ .indexOf( check ) > -1;
+ }
+ if ( operator === "|=" ) {
+ return result === check || result.slice( 0, check.length + 1 ) === check + "-";
+ }
+ return false;
};
},
- "CHILD": function( type, what, _argument, first, last ) {
+ CHILD: function( type, what, _argument, first, last ) {
var simple = type.slice( 0, 3 ) !== "nth",
forward = type.slice( -4 ) !== "last",
ofType = what === "of-type";
@@ -1962,7 +1703,7 @@ Expr = Sizzle.selectors = {
} :
function( elem, _context, xml ) {
- var cache, uniqueCache, outerCache, node, nodeIndex, start,
+ var cache, outerCache, node, nodeIndex, start,
dir = simple !== forward ? "nextSibling" : "previousSibling",
parent = elem.parentNode,
name = ofType && elem.nodeName.toLowerCase(),
@@ -1977,7 +1718,7 @@ Expr = Sizzle.selectors = {
node = elem;
while ( ( node = node[ dir ] ) ) {
if ( ofType ?
- node.nodeName.toLowerCase() === name :
+ nodeName( node, name ) :
node.nodeType === 1 ) {
return false;
@@ -1996,17 +1737,8 @@ Expr = Sizzle.selectors = {
if ( forward && useCache ) {
// Seek `elem` from a previously-cached index
-
- // ...in a gzip-friendly way
- node = parent;
- outerCache = node[ expando ] || ( node[ expando ] = {} );
-
- // Support: IE <9 only
- // Defend against cloned attroperties (jQuery gh-1709)
- uniqueCache = outerCache[ node.uniqueID ] ||
- ( outerCache[ node.uniqueID ] = {} );
-
- cache = uniqueCache[ type ] || [];
+ outerCache = parent[ expando ] || ( parent[ expando ] = {} );
+ cache = outerCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex && cache[ 2 ];
node = nodeIndex && parent.childNodes[ nodeIndex ];
@@ -2018,7 +1750,7 @@ Expr = Sizzle.selectors = {
// When found, cache indexes on `parent` and break
if ( node.nodeType === 1 && ++diff && node === elem ) {
- uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
break;
}
}
@@ -2027,17 +1759,8 @@ Expr = Sizzle.selectors = {
// Use previously-cached element index if available
if ( useCache ) {
-
- // ...in a gzip-friendly way
- node = elem;
- outerCache = node[ expando ] || ( node[ expando ] = {} );
-
- // Support: IE <9 only
- // Defend against cloned attroperties (jQuery gh-1709)
- uniqueCache = outerCache[ node.uniqueID ] ||
- ( outerCache[ node.uniqueID ] = {} );
-
- cache = uniqueCache[ type ] || [];
+ outerCache = elem[ expando ] || ( elem[ expando ] = {} );
+ cache = outerCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex;
}
@@ -2051,7 +1774,7 @@ Expr = Sizzle.selectors = {
( diff = nodeIndex = 0 ) || start.pop() ) ) {
if ( ( ofType ?
- node.nodeName.toLowerCase() === name :
+ nodeName( node, name ) :
node.nodeType === 1 ) &&
++diff ) {
@@ -2059,13 +1782,7 @@ Expr = Sizzle.selectors = {
if ( useCache ) {
outerCache = node[ expando ] ||
( node[ expando ] = {} );
-
- // Support: IE <9 only
- // Defend against cloned attroperties (jQuery gh-1709)
- uniqueCache = outerCache[ node.uniqueID ] ||
- ( outerCache[ node.uniqueID ] = {} );
-
- uniqueCache[ type ] = [ dirruns, diff ];
+ outerCache[ type ] = [ dirruns, diff ];
}
if ( node === elem ) {
@@ -2083,19 +1800,19 @@ Expr = Sizzle.selectors = {
};
},
- "PSEUDO": function( pseudo, argument ) {
+ PSEUDO: function( pseudo, argument ) {
// pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
+ // https://www.w3.org/TR/selectors/#pseudo-classes
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
// Remember that setFilters inherits from pseudos
var args,
fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
- Sizzle.error( "unsupported pseudo: " + pseudo );
+ find.error( "unsupported pseudo: " + pseudo );
// The user may use createPseudo to indicate that
// arguments are needed to create the filter function
- // just as Sizzle does
+ // just as jQuery does
if ( fn[ expando ] ) {
return fn( argument );
}
@@ -2109,7 +1826,7 @@ Expr = Sizzle.selectors = {
matched = fn( seed, argument ),
i = matched.length;
while ( i-- ) {
- idx = indexOf( seed, matched[ i ] );
+ idx = indexOf.call( seed, matched[ i ] );
seed[ idx ] = !( matches[ idx ] = matched[ i ] );
}
} ) :
@@ -2125,14 +1842,14 @@ Expr = Sizzle.selectors = {
pseudos: {
// Potentially complex pseudos
- "not": markFunction( function( selector ) {
+ not: markFunction( function( selector ) {
// Trim the selector passed to compile
// to avoid treating leading and trailing
// spaces as combinators
var input = [],
results = [],
- matcher = compile( selector.replace( rtrim, "$1" ) );
+ matcher = compile( selector.replace( rtrimCSS, "$1" ) );
return matcher[ expando ] ?
markFunction( function( seed, matches, _context, xml ) {
@@ -2151,22 +1868,23 @@ Expr = Sizzle.selectors = {
input[ 0 ] = elem;
matcher( input, null, xml, results );
- // Don't keep the element (issue #299)
+ // Don't keep the element
+ // (see https://github.com/jquery/sizzle/issues/299)
input[ 0 ] = null;
return !results.pop();
};
} ),
- "has": markFunction( function( selector ) {
+ has: markFunction( function( selector ) {
return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
+ return find( selector, elem ).length > 0;
};
} ),
- "contains": markFunction( function( text ) {
+ contains: markFunction( function( text ) {
text = text.replace( runescape, funescape );
return function( elem ) {
- return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
+ return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;
};
} ),
@@ -2176,12 +1894,12 @@ Expr = Sizzle.selectors = {
// or beginning with the identifier C immediately followed by "-".
// The matching of C against the element's language value is performed case-insensitively.
// The identifier C does not have to be a valid language name."
- // http://www.w3.org/TR/selectors/#lang-pseudo
- "lang": markFunction( function( lang ) {
+ // https://www.w3.org/TR/selectors/#lang-pseudo
+ lang: markFunction( function( lang ) {
// lang value must be a valid identifier
if ( !ridentifier.test( lang || "" ) ) {
- Sizzle.error( "unsupported lang: " + lang );
+ find.error( "unsupported lang: " + lang );
}
lang = lang.replace( runescape, funescape ).toLowerCase();
return function( elem ) {
@@ -2200,38 +1918,39 @@ Expr = Sizzle.selectors = {
} ),
// Miscellaneous
- "target": function( elem ) {
+ target: function( elem ) {
var hash = window.location && window.location.hash;
return hash && hash.slice( 1 ) === elem.id;
},
- "root": function( elem ) {
- return elem === docElem;
+ root: function( elem ) {
+ return elem === documentElement;
},
- "focus": function( elem ) {
- return elem === document.activeElement &&
- ( !document.hasFocus || document.hasFocus() ) &&
+ focus: function( elem ) {
+ return elem === safeActiveElement() &&
+ document.hasFocus() &&
!!( elem.type || elem.href || ~elem.tabIndex );
},
// Boolean properties
- "enabled": createDisabledPseudo( false ),
- "disabled": createDisabledPseudo( true ),
+ enabled: createDisabledPseudo( false ),
+ disabled: createDisabledPseudo( true ),
- "checked": function( elem ) {
+ checked: function( elem ) {
// In CSS3, :checked should return both checked and selected elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- var nodeName = elem.nodeName.toLowerCase();
- return ( nodeName === "input" && !!elem.checked ) ||
- ( nodeName === "option" && !!elem.selected );
+ // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ return ( nodeName( elem, "input" ) && !!elem.checked ) ||
+ ( nodeName( elem, "option" ) && !!elem.selected );
},
- "selected": function( elem ) {
+ selected: function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
+ // Support: IE <=11+
+ // Accessing the selectedIndex property
+ // forces the browser to treat the default option as
+ // selected when in an optgroup.
if ( elem.parentNode ) {
// eslint-disable-next-line no-unused-expressions
elem.parentNode.selectedIndex;
@@ -2241,9 +1960,9 @@ Expr = Sizzle.selectors = {
},
// Contents
- "empty": function( elem ) {
+ empty: function( elem ) {
- // http://www.w3.org/TR/selectors/#empty-pseudo
+ // https://www.w3.org/TR/selectors/#empty-pseudo
// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
// but not by others (comment: 8; processing instruction: 7; etc.)
// nodeType < 6 works because attributes (2) do not appear as children
@@ -2255,49 +1974,49 @@ Expr = Sizzle.selectors = {
return true;
},
- "parent": function( elem ) {
- return !Expr.pseudos[ "empty" ]( elem );
+ parent: function( elem ) {
+ return !Expr.pseudos.empty( elem );
},
// Element/input types
- "header": function( elem ) {
+ header: function( elem ) {
return rheader.test( elem.nodeName );
},
- "input": function( elem ) {
+ input: function( elem ) {
return rinputs.test( elem.nodeName );
},
- "button": function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === "button" || name === "button";
+ button: function( elem ) {
+ return nodeName( elem, "input" ) && elem.type === "button" ||
+ nodeName( elem, "button" );
},
- "text": function( elem ) {
+ text: function( elem ) {
var attr;
- return elem.nodeName.toLowerCase() === "input" &&
- elem.type === "text" &&
+ return nodeName( elem, "input" ) && elem.type === "text" &&
// Support: IE <10 only
- // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ // New HTML5 attribute values (e.g., "search") appear
+ // with elem.type === "text"
( ( attr = elem.getAttribute( "type" ) ) == null ||
attr.toLowerCase() === "text" );
},
// Position-in-collection
- "first": createPositionalPseudo( function() {
+ first: createPositionalPseudo( function() {
return [ 0 ];
} ),
- "last": createPositionalPseudo( function( _matchIndexes, length ) {
+ last: createPositionalPseudo( function( _matchIndexes, length ) {
return [ length - 1 ];
} ),
- "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) {
+ eq: createPositionalPseudo( function( _matchIndexes, length, argument ) {
return [ argument < 0 ? argument + length : argument ];
} ),
- "even": createPositionalPseudo( function( matchIndexes, length ) {
+ even: createPositionalPseudo( function( matchIndexes, length ) {
var i = 0;
for ( ; i < length; i += 2 ) {
matchIndexes.push( i );
@@ -2305,7 +2024,7 @@ Expr = Sizzle.selectors = {
return matchIndexes;
} ),
- "odd": createPositionalPseudo( function( matchIndexes, length ) {
+ odd: createPositionalPseudo( function( matchIndexes, length ) {
var i = 1;
for ( ; i < length; i += 2 ) {
matchIndexes.push( i );
@@ -2313,19 +2032,24 @@ Expr = Sizzle.selectors = {
return matchIndexes;
} ),
- "lt": createPositionalPseudo( function( matchIndexes, length, argument ) {
- var i = argument < 0 ?
- argument + length :
- argument > length ?
- length :
- argument;
+ lt: createPositionalPseudo( function( matchIndexes, length, argument ) {
+ var i;
+
+ if ( argument < 0 ) {
+ i = argument + length;
+ } else if ( argument > length ) {
+ i = length;
+ } else {
+ i = argument;
+ }
+
for ( ; --i >= 0; ) {
matchIndexes.push( i );
}
return matchIndexes;
} ),
- "gt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+ gt: createPositionalPseudo( function( matchIndexes, length, argument ) {
var i = argument < 0 ? argument + length : argument;
for ( ; ++i < length; ) {
matchIndexes.push( i );
@@ -2335,7 +2059,7 @@ Expr = Sizzle.selectors = {
}
};
-Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ];
+Expr.pseudos.nth = Expr.pseudos.eq;
// Add button/input type pseudos
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
@@ -2350,7 +2074,7 @@ function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();
-tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+function tokenize( selector, parseOnly ) {
var matched, match, tokens, type,
soFar, groups, preFilters,
cached = tokenCache[ selector + " " ];
@@ -2384,7 +2108,7 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
value: matched,
// Cast descendant combinators to space
- type: match[ 0 ].replace( rtrim, " " )
+ type: match[ 0 ].replace( rtrimCSS, " " )
} );
soFar = soFar.slice( matched.length );
}
@@ -2411,14 +2135,16 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
// Return the length of the invalid excess
// if we're just parsing
// Otherwise, throw an error or return tokens
- return parseOnly ?
- soFar.length :
- soFar ?
- Sizzle.error( selector ) :
+ if ( parseOnly ) {
+ return soFar.length;
+ }
- // Cache the tokens
- tokenCache( selector, groups ).slice( 0 );
-};
+ return soFar ?
+ find.error( selector ) :
+
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
function toSelector( tokens ) {
var i = 0,
@@ -2451,7 +2177,7 @@ function addCombinator( matcher, combinator, base ) {
// Check against all ancestor/preceding elements
function( elem, context, xml ) {
- var oldCache, uniqueCache, outerCache,
+ var oldCache, outerCache,
newCache = [ dirruns, doneName ];
// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
@@ -2468,14 +2194,9 @@ function addCombinator( matcher, combinator, base ) {
if ( elem.nodeType === 1 || checkNonElements ) {
outerCache = elem[ expando ] || ( elem[ expando ] = {} );
- // Support: IE <9 only
- // Defend against cloned attroperties (jQuery gh-1709)
- uniqueCache = outerCache[ elem.uniqueID ] ||
- ( outerCache[ elem.uniqueID ] = {} );
-
- if ( skip && skip === elem.nodeName.toLowerCase() ) {
+ if ( skip && nodeName( elem, skip ) ) {
elem = elem[ dir ] || elem;
- } else if ( ( oldCache = uniqueCache[ key ] ) &&
+ } else if ( ( oldCache = outerCache[ key ] ) &&
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
// Assign to newCache so results back-propagate to previous elements
@@ -2483,7 +2204,7 @@ function addCombinator( matcher, combinator, base ) {
} else {
// Reuse newcache so results back-propagate to previous elements
- uniqueCache[ key ] = newCache;
+ outerCache[ key ] = newCache;
// A match means we're done; a fail means we have to keep checking
if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
@@ -2515,7 +2236,7 @@ function multipleContexts( selector, contexts, results ) {
var i = 0,
len = contexts.length;
for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[ i ], results );
+ find( selector, contexts[ i ], results );
}
return results;
}
@@ -2549,38 +2270,37 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS
postFinder = setMatcher( postFinder, postSelector );
}
return markFunction( function( seed, results, context, xml ) {
- var temp, i, elem,
+ var temp, i, elem, matcherOut,
preMap = [],
postMap = [],
preexisting = results.length,
// Get initial elements from seed or context
- elems = seed || multipleContexts(
- selector || "*",
- context.nodeType ? [ context ] : context,
- []
- ),
+ elems = seed ||
+ multipleContexts( selector || "*",
+ context.nodeType ? [ context ] : context, [] ),
// Prefilter to get matcher input, preserving a map for seed-results synchronization
matcherIn = preFilter && ( seed || !selector ) ?
condense( elems, preMap, preFilter, context, xml ) :
- elems,
+ elems;
- matcherOut = matcher ?
+ if ( matcher ) {
- // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
- postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter
+ // or preexisting results,
+ matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
- // ...intermediate processing is necessary
- [] :
+ // ...intermediate processing is necessary
+ [] :
- // ...otherwise use results directly
- results :
- matcherIn;
+ // ...otherwise use results directly
+ results;
- // Find primary matches
- if ( matcher ) {
+ // Find primary matches
matcher( matcherIn, matcherOut, context, xml );
+ } else {
+ matcherOut = matcherIn;
}
// Apply postFilter
@@ -2618,7 +2338,7 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS
i = matcherOut.length;
while ( i-- ) {
if ( ( elem = matcherOut[ i ] ) &&
- ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {
+ ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) {
seed[ temp ] = !( results[ temp ] = elem );
}
@@ -2653,15 +2373,21 @@ function matcherFromTokens( tokens ) {
return elem === checkContext;
}, implicitRelative, true ),
matchAnyContext = addCombinator( function( elem ) {
- return indexOf( checkContext, elem ) > -1;
+ return indexOf.call( checkContext, elem ) > -1;
}, implicitRelative, true ),
matchers = [ function( elem, context, xml ) {
- var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || (
( checkContext = context ).nodeType ?
matchContext( elem, context, xml ) :
matchAnyContext( elem, context, xml ) );
- // Avoid hanging onto element (issue #299)
+ // Avoid hanging onto element
+ // (see https://github.com/jquery/sizzle/issues/299)
checkContext = null;
return ret;
} ];
@@ -2686,11 +2412,10 @@ function matcherFromTokens( tokens ) {
i > 1 && elementMatcher( matchers ),
i > 1 && toSelector(
- // If the preceding token was a descendant combinator, insert an implicit any-element `*`
- tokens
- .slice( 0, i - 1 )
- .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
- ).replace( rtrim, "$1" ),
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 )
+ .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
+ ).replace( rtrimCSS, "$1" ),
matcher,
i < j && matcherFromTokens( tokens.slice( i, j ) ),
j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
@@ -2716,7 +2441,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
contextBackup = outermostContext,
// We must always have either seed elements or outermost context
- elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ),
+ elems = seed || byElement && Expr.find.TAG( "*", outermost ),
// Use integer dirruns iff this is the outermost matcher
dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),
@@ -2732,8 +2457,9 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
}
// Add elements passing elementMatchers directly to results
- // Support: IE<9, Safari
- // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ // Support: iOS <=7 - 9 only
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching
+ // elements by id. (see trac-14142)
for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {
if ( byElement && elem ) {
j = 0;
@@ -2748,7 +2474,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
}
while ( ( matcher = elementMatchers[ j++ ] ) ) {
if ( matcher( elem, context || document, xml ) ) {
- results.push( elem );
+ push.call( results, elem );
break;
}
}
@@ -2811,7 +2537,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
if ( outermost && !seed && setMatched.length > 0 &&
( matchedCount + setMatchers.length ) > 1 ) {
- Sizzle.uniqueSort( results );
+ jQuery.uniqueSort( results );
}
}
@@ -2829,7 +2555,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
superMatcher;
}
-compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+function compile( selector, match /* Internal Use Only */ ) {
var i,
setMatchers = [],
elementMatchers = [],
@@ -2852,27 +2578,25 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
}
// Cache the compiled function
- cached = compilerCache(
- selector,
- matcherFromGroupMatchers( elementMatchers, setMatchers )
- );
+ cached = compilerCache( selector,
+ matcherFromGroupMatchers( elementMatchers, setMatchers ) );
// Save selector and tokenization
cached.selector = selector;
}
return cached;
-};
+}
/**
- * A low-level selection function that works with Sizzle's compiled
+ * A low-level selection function that works with jQuery's compiled
* selector functions
* @param {String|Function} selector A selector or a pre-compiled
- * selector function built with Sizzle.compile
+ * selector function built with jQuery selector compile
* @param {Element} context
* @param {Array} [results]
* @param {Array} [seed] A set of elements to match against
*/
-select = Sizzle.select = function( selector, context, results, seed ) {
+function select( selector, context, results, seed ) {
var i, tokens, token, type, find,
compiled = typeof selector === "function" && selector,
match = !seed && tokenize( ( selector = compiled.selector || selector ) );
@@ -2886,10 +2610,12 @@ select = Sizzle.select = function( selector, context, results, seed ) {
// Reduce context if the leading compound selector is an ID
tokens = match[ 0 ] = match[ 0 ].slice( 0 );
if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
- context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
+ context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
- context = ( Expr.find[ "ID" ]( token.matches[ 0 ]
- .replace( runescape, funescape ), context ) || [] )[ 0 ];
+ context = ( Expr.find.ID(
+ token.matches[ 0 ].replace( runescape, funescape ),
+ context
+ ) || [] )[ 0 ];
if ( !context ) {
return results;
@@ -2902,7 +2628,7 @@ select = Sizzle.select = function( selector, context, results, seed ) {
}
// Fetch a seed set for right-to-left matching
- i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length;
+ i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length;
while ( i-- ) {
token = tokens[ i ];
@@ -2915,8 +2641,8 @@ select = Sizzle.select = function( selector, context, results, seed ) {
// Search, expanding context for leading sibling combinators
if ( ( seed = find(
token.matches[ 0 ].replace( runescape, funescape ),
- rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||
- context
+ rsibling.test( tokens[ 0 ].type ) &&
+ testContext( context.parentNode ) || context
) ) ) {
// If seed is empty or no tokens remain, we can return early
@@ -2943,21 +2669,18 @@ select = Sizzle.select = function( selector, context, results, seed ) {
!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
);
return results;
-};
+}
// One-time assignments
+// Support: Android <=4.0 - 4.1+
// Sort stability
support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;
-// Support: Chrome 14-35+
-// Always assume duplicates if they aren't passed to the comparison function
-support.detectDuplicates = !!hasDuplicate;
-
// Initialize against the default document
setDocument();
-// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Support: Android <=4.0 - 4.1+
// Detached nodes confoundingly follow *each other*
support.sortDetached = assert( function( el ) {
@@ -2965,68 +2688,29 @@ support.sortDetached = assert( function( el ) {
return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1;
} );
-// Support: IE<8
-// Prevent attribute/property "interpolation"
-// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !assert( function( el ) {
- el.innerHTML = "<a href='#'></a>";
- return el.firstChild.getAttribute( "href" ) === "#";
-} ) ) {
- addHandle( "type|href|height|width", function( elem, name, isXML ) {
- if ( !isXML ) {
- return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
- }
- } );
-}
-
-// Support: IE<9
-// Use defaultValue in place of getAttribute("value")
-if ( !support.attributes || !assert( function( el ) {
- el.innerHTML = "<input/>";
- el.firstChild.setAttribute( "value", "" );
- return el.firstChild.getAttribute( "value" ) === "";
-} ) ) {
- addHandle( "value", function( elem, _name, isXML ) {
- if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
- return elem.defaultValue;
- }
- } );
-}
-
-// Support: IE<9
-// Use getAttributeNode to fetch booleans when getAttribute lies
-if ( !assert( function( el ) {
- return el.getAttribute( "disabled" ) == null;
-} ) ) {
- addHandle( booleans, function( elem, name, isXML ) {
- var val;
- if ( !isXML ) {
- return elem[ name ] === true ? name.toLowerCase() :
- ( val = elem.getAttributeNode( name ) ) && val.specified ?
- val.value :
- null;
- }
- } );
-}
-
-return Sizzle;
-
-} )( window );
-
-
-
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
+jQuery.find = find;
// Deprecated
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
-jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-jQuery.escapeSelector = Sizzle.escape;
+jQuery.unique = jQuery.uniqueSort;
+// These have always been private, but they used to be documented
+// as part of Sizzle so let's maintain them in the 3.x line
+// for backwards compatibility purposes.
+find.compile = compile;
+find.select = select;
+find.setDocument = setDocument;
+find.escape = jQuery.escapeSelector;
+find.getText = jQuery.text;
+find.isXML = jQuery.isXMLDoc;
+find.selectors = jQuery.expr;
+find.support = jQuery.support;
+find.uniqueSort = jQuery.uniqueSort;
+
+ /* eslint-enable */
+
+} )();
var dir = function( elem, dir, until ) {
@@ -3060,13 +2744,6 @@ var siblings = function( n, elem ) {
var rneedsContext = jQuery.expr.match.needsContext;
-
-
-function nodeName( elem, name ) {
-
- return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
-
-}
var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
@@ -3317,7 +2994,7 @@ jQuery.fn.extend( {
if ( cur.nodeType < 11 && ( targets ?
targets.index( cur ) > -1 :
- // Don't pass non-elements to Sizzle
+ // Don't pass non-elements to jQuery#find
cur.nodeType === 1 &&
jQuery.find.matchesSelector( cur, selectors ) ) ) {
@@ -3872,7 +3549,7 @@ jQuery.extend( {
if ( jQuery.Deferred.exceptionHook ) {
jQuery.Deferred.exceptionHook( e,
- process.stackTrace );
+ process.error );
}
// Support: Promises/A+ section 2.3.3.3.4.1
@@ -3900,10 +3577,17 @@ jQuery.extend( {
process();
} else {
- // Call an optional hook to record the stack, in case of exception
+ // Call an optional hook to record the error, in case of exception
// since it's otherwise lost when execution goes async
- if ( jQuery.Deferred.getStackHook ) {
- process.stackTrace = jQuery.Deferred.getStackHook();
+ if ( jQuery.Deferred.getErrorHook ) {
+ process.error = jQuery.Deferred.getErrorHook();
+
+ // The deprecated alias of the above. While the name suggests
+ // returning the stack, not an error instance, jQuery just passes
+ // it directly to `console.warn` so both will work; an instance
+ // just better cooperates with source maps.
+ } else if ( jQuery.Deferred.getStackHook ) {
+ process.error = jQuery.Deferred.getStackHook();
}
window.setTimeout( process );
}
@@ -4078,12 +3762,16 @@ jQuery.extend( {
// warn about them ASAP rather than swallowing them by default.
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
-jQuery.Deferred.exceptionHook = function( error, stack ) {
+// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error
+// captured before the async barrier to get the original error cause
+// which may otherwise be hidden.
+jQuery.Deferred.exceptionHook = function( error, asyncError ) {
// Support: IE 8 - 9 only
// Console exists when dev tools are open, which can happen at any time
if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
- window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
+ window.console.warn( "jQuery.Deferred exception: " + error.message,
+ error.stack, asyncError );
}
};
@@ -5139,25 +4827,6 @@ function returnFalse() {
return false;
}
-// Support: IE <=9 - 11+
-// focus() and blur() are asynchronous, except when they are no-op.
-// So expect focus to be synchronous when the element is already active,
-// and blur to be synchronous when the element is not already active.
-// (focus and blur are always synchronous in other supported browsers,
-// this just defines when we can count on it).
-function expectSync( elem, type ) {
- return ( elem === safeActiveElement() ) === ( type === "focus" );
-}
-
-// Support: IE <=9 only
-// Accessing document.activeElement can throw unexpectedly
-// https://bugs.jquery.com/ticket/13393
-function safeActiveElement() {
- try {
- return document.activeElement;
- } catch ( err ) { }
-}
-
function on( elem, types, selector, data, fn, one ) {
var origFn, type;
@@ -5595,7 +5264,7 @@ jQuery.event = {
el.click && nodeName( el, "input" ) ) {
// dataPriv.set( el, "click", ... )
- leverageNative( el, "click", returnTrue );
+ leverageNative( el, "click", true );
}
// Return false to allow normal processing in the caller
@@ -5646,10 +5315,10 @@ jQuery.event = {
// synthetic events by interrupting progress until reinvoked in response to
// *native* events that it fires directly, ensuring that state changes have
// already occurred before other listeners are invoked.
-function leverageNative( el, type, expectSync ) {
+function leverageNative( el, type, isSetup ) {
- // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
- if ( !expectSync ) {
+ // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add
+ if ( !isSetup ) {
if ( dataPriv.get( el, type ) === undefined ) {
jQuery.event.add( el, type, returnTrue );
}
@@ -5661,15 +5330,13 @@ function leverageNative( el, type, expectSync ) {
jQuery.event.add( el, type, {
namespace: false,
handler: function( event ) {
- var notAsync, result,
+ var result,
saved = dataPriv.get( this, type );
if ( ( event.isTrigger & 1 ) && this[ type ] ) {
// Interrupt processing of the outer synthetic .trigger()ed event
- // Saved data should be false in such cases, but might be a leftover capture object
- // from an async native handler (gh-4350)
- if ( !saved.length ) {
+ if ( !saved ) {
// Store arguments for use when handling the inner native event
// There will always be at least one argument (an event object), so this array
@@ -5678,33 +5345,22 @@ function leverageNative( el, type, expectSync ) {
dataPriv.set( this, type, saved );
// Trigger the native event and capture its result
- // Support: IE <=9 - 11+
- // focus() and blur() are asynchronous
- notAsync = expectSync( this, type );
this[ type ]();
result = dataPriv.get( this, type );
- if ( saved !== result || notAsync ) {
- dataPriv.set( this, type, false );
- } else {
- result = {};
- }
+ dataPriv.set( this, type, false );
+
if ( saved !== result ) {
// Cancel the outer synthetic event
event.stopImmediatePropagation();
event.preventDefault();
- // Support: Chrome 86+
- // In Chrome, if an element having a focusout handler is blurred by
- // clicking outside of it, it invokes the handler synchronously. If
- // that handler calls `.remove()` on the element, the data is cleared,
- // leaving `result` undefined. We need to guard against this.
- return result && result.value;
+ return result;
}
// If this is an inner synthetic event for an event with a bubbling surrogate
- // (focus or blur), assume that the surrogate already propagated from triggering the
- // native event and prevent that from happening again here.
+ // (focus or blur), assume that the surrogate already propagated from triggering
+ // the native event and prevent that from happening again here.
// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
// bubbling surrogate propagates *after* the non-bubbling base), but that seems
// less bad than duplication.
@@ -5714,22 +5370,25 @@ function leverageNative( el, type, expectSync ) {
// If this is a native event triggered above, everything is now in order
// Fire an inner synthetic event with the original arguments
- } else if ( saved.length ) {
+ } else if ( saved ) {
// ...and capture the result
- dataPriv.set( this, type, {
- value: jQuery.event.trigger(
-
- // Support: IE <=9 - 11+
- // Extend with the prototype to reset the above stopImmediatePropagation()
- jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
- saved.slice( 1 ),
- this
- )
- } );
-
- // Abort handling of the native event
- event.stopImmediatePropagation();
+ dataPriv.set( this, type, jQuery.event.trigger(
+ saved[ 0 ],
+ saved.slice( 1 ),
+ this
+ ) );
+
+ // Abort handling of the native event by all jQuery handlers while allowing
+ // native handlers on the same element to run. On target, this is achieved
+ // by stopping immediate propagation just on the jQuery event. However,
+ // the native event is re-wrapped by a jQuery one on each level of the
+ // propagation so the only way to stop it for jQuery is to stop it for
+ // everyone via native `stopPropagation()`. This is not a problem for
+ // focus/blur which don't bubble, but it does also stop click on checkboxes
+ // and radios. We accept this limitation.
+ event.stopPropagation();
+ event.isImmediatePropagationStopped = returnTrue;
}
}
} );
@@ -5868,18 +5527,73 @@ jQuery.each( {
}, jQuery.event.addProp );
jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
+
+ function focusMappedHandler( nativeEvent ) {
+ if ( document.documentMode ) {
+
+ // Support: IE 11+
+ // Attach a single focusin/focusout handler on the document while someone wants
+ // focus/blur. This is because the former are synchronous in IE while the latter
+ // are async. In other browsers, all those handlers are invoked synchronously.
+
+ // `handle` from private data would already wrap the event, but we need
+ // to change the `type` here.
+ var handle = dataPriv.get( this, "handle" ),
+ event = jQuery.event.fix( nativeEvent );
+ event.type = nativeEvent.type === "focusin" ? "focus" : "blur";
+ event.isSimulated = true;
+
+ // First, handle focusin/focusout
+ handle( nativeEvent );
+
+ // ...then, handle focus/blur
+ //
+ // focus/blur don't bubble while focusin/focusout do; simulate the former by only
+ // invoking the handler at the lower level.
+ if ( event.target === event.currentTarget ) {
+
+ // The setup part calls `leverageNative`, which, in turn, calls
+ // `jQuery.event.add`, so event handle will already have been set
+ // by this point.
+ handle( event );
+ }
+ } else {
+
+ // For non-IE browsers, attach a single capturing handler on the document
+ // while someone wants focusin/focusout.
+ jQuery.event.simulate( delegateType, nativeEvent.target,
+ jQuery.event.fix( nativeEvent ) );
+ }
+ }
+
jQuery.event.special[ type ] = {
// Utilize native event if possible so blur/focus sequence is correct
setup: function() {
+ var attaches;
+
// Claim the first handler
// dataPriv.set( this, "focus", ... )
// dataPriv.set( this, "blur", ... )
- leverageNative( this, type, expectSync );
+ leverageNative( this, type, true );
- // Return false to allow normal processing in the caller
- return false;
+ if ( document.documentMode ) {
+
+ // Support: IE 9 - 11+
+ // We use the same native handler for focusin & focus (and focusout & blur)
+ // so we need to coordinate setup & teardown parts between those events.
+ // Use `delegateType` as the key as `type` is already used by `leverageNative`.
+ attaches = dataPriv.get( this, delegateType );
+ if ( !attaches ) {
+ this.addEventListener( delegateType, focusMappedHandler );
+ }
+ dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 );
+ } else {
+
+ // Return false to allow normal processing in the caller
+ return false;
+ }
},
trigger: function() {
@@ -5890,6 +5604,24 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
return true;
},
+ teardown: function() {
+ var attaches;
+
+ if ( document.documentMode ) {
+ attaches = dataPriv.get( this, delegateType ) - 1;
+ if ( !attaches ) {
+ this.removeEventListener( delegateType, focusMappedHandler );
+ dataPriv.remove( this, delegateType );
+ } else {
+ dataPriv.set( this, delegateType, attaches );
+ }
+ } else {
+
+ // Return false to indicate standard teardown should be applied
+ return false;
+ }
+ },
+
// Suppress native focus or blur if we're currently inside
// a leveraged native-event stack
_default: function( event ) {
@@ -5898,6 +5630,58 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
delegateType: delegateType
};
+
+ // Support: Firefox <=44
+ // Firefox doesn't have focus(in | out) events
+ // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+ //
+ // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
+ // focus(in | out) events fire after focus & blur events,
+ // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
+ // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
+ //
+ // Support: IE 9 - 11+
+ // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch,
+ // attach a single handler for both events in IE.
+ jQuery.event.special[ delegateType ] = {
+ setup: function() {
+
+ // Handle: regular nodes (via `this.ownerDocument`), window
+ // (via `this.document`) & document (via `this`).
+ var doc = this.ownerDocument || this.document || this,
+ dataHolder = document.documentMode ? this : doc,
+ attaches = dataPriv.get( dataHolder, delegateType );
+
+ // Support: IE 9 - 11+
+ // We use the same native handler for focusin & focus (and focusout & blur)
+ // so we need to coordinate setup & teardown parts between those events.
+ // Use `delegateType` as the key as `type` is already used by `leverageNative`.
+ if ( !attaches ) {
+ if ( document.documentMode ) {
+ this.addEventListener( delegateType, focusMappedHandler );
+ } else {
+ doc.addEventListener( type, focusMappedHandler, true );
+ }
+ }
+ dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this.document || this,
+ dataHolder = document.documentMode ? this : doc,
+ attaches = dataPriv.get( dataHolder, delegateType ) - 1;
+
+ if ( !attaches ) {
+ if ( document.documentMode ) {
+ this.removeEventListener( delegateType, focusMappedHandler );
+ } else {
+ doc.removeEventListener( type, focusMappedHandler, true );
+ }
+ dataPriv.remove( dataHolder, delegateType );
+ } else {
+ dataPriv.set( dataHolder, delegateType, attaches );
+ }
+ }
+ };
} );
// Create mouseenter/leave events using mouseover/out and event-time checks
@@ -6200,7 +5984,8 @@ jQuery.extend( {
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
!jQuery.isXMLDoc( elem ) ) {
- // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
+ // We eschew jQuery#find here for performance reasons:
+ // https://jsperf.com/getall-vs-sizzle/2
destElements = getAll( clone );
srcElements = getAll( elem );
@@ -6476,15 +6261,6 @@ var swap = function( elem, options, callback ) {
var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
-var whitespace = "[\\x20\\t\\r\\n\\f]";
-
-
-var rtrimCSS = new RegExp(
- "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$",
- "g"
-);
-
-
( function() {
@@ -6793,7 +6569,8 @@ function setPositiveNumber( _elem, value, subtract ) {
function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
var i = dimension === "width" ? 1 : 0,
extra = 0,
- delta = 0;
+ delta = 0,
+ marginDelta = 0;
// Adjustment may not be necessary
if ( box === ( isBorderBox ? "border" : "content" ) ) {
@@ -6803,8 +6580,10 @@ function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computed
for ( ; i < 4; i += 2 ) {
// Both box models exclude margin
+ // Count margin delta separately to only add it after scroll gutter adjustment.
+ // This is needed to make negative margins work with `outerHeight( true )` (gh-3982).
if ( box === "margin" ) {
- delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
+ marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
}
// If we get here with a content-box, we're seeking "padding" or "border" or "margin"
@@ -6855,7 +6634,7 @@ function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computed
) ) || 0;
}
- return delta;
+ return delta + marginDelta;
}
function getWidthOrHeight( elem, dimension, extra ) {
@@ -6953,26 +6732,35 @@ jQuery.extend( {
// Don't automatically add "px" to these possibly-unitless properties
cssNumber: {
- "animationIterationCount": true,
- "columnCount": true,
- "fillOpacity": true,
- "flexGrow": true,
- "flexShrink": true,
- "fontWeight": true,
- "gridArea": true,
- "gridColumn": true,
- "gridColumnEnd": true,
- "gridColumnStart": true,
- "gridRow": true,
- "gridRowEnd": true,
- "gridRowStart": true,
- "lineHeight": true,
- "opacity": true,
- "order": true,
- "orphans": true,
- "widows": true,
- "zIndex": true,
- "zoom": true
+ animationIterationCount: true,
+ aspectRatio: true,
+ borderImageSlice: true,
+ columnCount: true,
+ flexGrow: true,
+ flexShrink: true,
+ fontWeight: true,
+ gridArea: true,
+ gridColumn: true,
+ gridColumnEnd: true,
+ gridColumnStart: true,
+ gridRow: true,
+ gridRowEnd: true,
+ gridRowStart: true,
+ lineHeight: true,
+ opacity: true,
+ order: true,
+ orphans: true,
+ scale: true,
+ widows: true,
+ zIndex: true,
+ zoom: true,
+
+ // SVG-related
+ fillOpacity: true,
+ floodOpacity: true,
+ stopOpacity: true,
+ strokeMiterlimit: true,
+ strokeOpacity: true
},
// Add in properties whose names you wish to fix before
@@ -7906,7 +7694,31 @@ jQuery.each( [ "radio", "checkbox" ], function() {
// Return jQuery for attributes-only inclusion
-support.focusin = "onfocusin" in window;
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml, parserErrorElem;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+
+ // Support: IE 9 - 11 only
+ // IE throws on parseFromString with invalid input.
+ try {
+ xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
+ } catch ( e ) {}
+
+ parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ];
+ if ( !xml || parserErrorElem ) {
+ jQuery.error( "Invalid XML: " + (
+ parserErrorElem ?
+ jQuery.map( parserErrorElem.childNodes, function( el ) {
+ return el.textContent;
+ } ).join( "\n" ) :
+ data
+ ) );
+ }
+ return xml;
+};
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
@@ -8094,79 +7906,6 @@ jQuery.fn.extend( {
} );
-// Support: Firefox <=44
-// Firefox doesn't have focus(in | out) events
-// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
-//
-// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
-// focus(in | out) events fire after focus & blur events,
-// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
-// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
-if ( !support.focusin ) {
- jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler on the document while someone wants focusin/focusout
- var handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
-
- // Handle: regular nodes (via `this.ownerDocument`), window
- // (via `this.document`) & document (via `this`).
- var doc = this.ownerDocument || this.document || this,
- attaches = dataPriv.access( doc, fix );
-
- if ( !attaches ) {
- doc.addEventListener( orig, handler, true );
- }
- dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
- },
- teardown: function() {
- var doc = this.ownerDocument || this.document || this,
- attaches = dataPriv.access( doc, fix ) - 1;
-
- if ( !attaches ) {
- doc.removeEventListener( orig, handler, true );
- dataPriv.remove( doc, fix );
-
- } else {
- dataPriv.access( doc, fix, attaches );
- }
- }
- };
- } );
-}
-
-
-// Cross-browser xml parsing
-jQuery.parseXML = function( data ) {
- var xml, parserErrorElem;
- if ( !data || typeof data !== "string" ) {
- return null;
- }
-
- // Support: IE 9 - 11 only
- // IE throws on parseFromString with invalid input.
- try {
- xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
- } catch ( e ) {}
-
- parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ];
- if ( !xml || parserErrorElem ) {
- jQuery.error( "Invalid XML: " + (
- parserErrorElem ?
- jQuery.map( parserErrorElem.childNodes, function( el ) {
- return el.textContent;
- } ).join( "\n" ) :
- data
- ) );
- }
- return xml;
-};
-
-
var
rbracket = /\[\]$/,
rCRLF = /\r?\n/g,
diff --git a/src/static/templates/admin/base.hbs b/src/static/templates/admin/base.hbs
index 2fe1ee54..5e713105 100644
--- a/src/static/templates/admin/base.hbs
+++ b/src/static/templates/admin/base.hbs
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<html lang="en">
+<html lang="en" data-bs-theme="auto">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -10,17 +10,17 @@
<link rel="stylesheet" href="{{urlpath}}/vw_static/admin.css" />
<script src="{{urlpath}}/vw_static/admin.js"></script>
</head>
-<body class="bg-light">
+<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 shadow fixed-top">
<div class="container-xl">
<a class="navbar-brand" href="{{urlpath}}/admin"><img class="vaultwarden-icon" src="{{urlpath}}/vw_static/vaultwarden-icon.png" alt="V">aultwarden Admin</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
- aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
+ aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto">
- {{#if logged_in}}
+ {{#if logged_in}}
<li class="nav-item">
<a class="nav-link" href="{{urlpath}}/admin">Settings</a>
</li>
@@ -33,15 +33,59 @@
<li class="nav-item">
<a class="nav-link" href="{{urlpath}}/admin/diagnostics">Diagnostics</a>
</li>
- {{/if}}
+ {{/if}}
<li class="nav-item">
<a class="nav-link" href="{{urlpath}}/" target="_blank" rel="noreferrer">Vault</a>
</li>
</ul>
+ <ul class="navbar-nav">
+ <li class="nav-item dropdown">
+ <button
+ class="btn btn-link nav-link py-0 px-0 px-md-2 dropdown-toggle d-flex align-items-center"
+ id="bd-theme" type="button" aria-expanded="false" data-bs-toggle="dropdown"
+ data-bs-display="static" aria-label="Toggle theme (auto)">
+ <span class="my-1 fs-4 theme-icon-active">
+ <use>&#9775;</use>
+ </span>
+ <span class="d-md-none ms-2" id="bd-theme-text">Toggle theme</span>
+ </button>
+ <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme-text">
+ <li>
+ <button type="button" class="dropdown-item d-flex align-items-center"
+ data-bs-theme-value="light" aria-pressed="false">
+ <span class="me-2 fs-4 theme-icon">
+ <use>&#9728;</use>
+ </span>
+ Light
+ </button>
+ </li>
+ <li>
+ <button type="button" class="dropdown-item d-flex align-items-center"
+ data-bs-theme-value="dark" aria-pressed="false">
+ <span class="me-2 fs-4 theme-icon">
+ <use>&starf;</use>
+ </span>
+ Dark
+ </button>
+ </li>
+ <li>
+ <button type="button" class="dropdown-item d-flex align-items-center active"
+ data-bs-theme-value="auto" aria-pressed="true">
+ <span class="me-2 fs-4 theme-icon">
+ <use>&#9775;</use>
+ </span>
+ Auto
+ </button>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
{{#if logged_in}}
- <a class="btn btn-sm btn-secondary" href="{{urlpath}}/admin/logout">Log Out</a>
+ <a class="btn btn-sm btn-secondary" href="{{urlpath}}/admin/logout">Log Out</a>
{{/if}}
+
</div>
</div>
</nav>
@@ -49,6 +93,6 @@
{{> (lookup this "page_content") }}
<!-- This script needs to be at the bottom, else it will fail! -->
- <script src="{{urlpath}}/vw_static/bootstrap-native.js"></script>
+ <script src="{{urlpath}}/vw_static/bootstrap.bundle.js"></script>
</body>
</html>
diff --git a/src/static/templates/admin/diagnostics.hbs b/src/static/templates/admin/diagnostics.hbs
index a61d8992..58c2889c 100644
--- a/src/static/templates/admin/diagnostics.hbs
+++ b/src/static/templates/admin/diagnostics.hbs
@@ -1,5 +1,5 @@
<main class="container-xl">
- <div id="diagnostics-block" class="my-3 p-3 bg-white rounded shadow">
+ <div id="diagnostics-block" class="my-3 p-3 rounded shadow">
<h6 class="border-bottom pb-2 mb-2">Diagnostics</h6>
<h3>Versions</h3>
@@ -8,8 +8,8 @@
<dl class="row">
<dt class="col-sm-5">Server Installed
<span class="badge bg-success d-none" id="server-success" title="Latest version is installed.">Ok</span>
- <span class="badge bg-warning d-none" id="server-warning" title="There seems to be an update available.">Update</span>
- <span class="badge bg-info d-none" id="server-branch" title="This is a branched version.">Branched</span>
+ <span class="badge bg-warning text-dark d-none" id="server-warning" title="There seems to be an update available.">Update</span>
+ <span class="badge bg-info text-dark d-none" id="server-branch" title="This is a branched version.">Branched</span>
</dt>
<dd class="col-sm-7">
<span id="server-installed">{{page_data.current_release}}</span>
diff --git a/src/static/templates/admin/login.hbs b/src/static/templates/admin/login.hbs
index 61d4daf9..3ea94aec 100644
--- a/src/static/templates/admin/login.hbs
+++ b/src/static/templates/admin/login.hbs
@@ -1,15 +1,15 @@
<main class="container-xl">
{{#if error}}
- <div class="align-items-center p-3 mb-3 text-white-50 bg-warning rounded shadow">
+ <div class="align-items-center p-3 mb-3 text-opacity-50 text-dark bg-warning rounded shadow">
<div>
- <h6 class="mb-0 text-white">{{error}}</h6>
+ <h6 class="mb-0 text-dark">{{error}}</h6>
</div>
</div>
{{/if}}
- <div class="align-items-center p-3 mb-3 text-white-50 bg-danger rounded shadow">
+ <div class="align-items-center p-3 mb-3 text-opacity-75 text-light bg-danger rounded shadow">
<div>
- <h6 class="mb-0 text-white">Authentication key needed to continue</h6>
+ <h6 class="mb-0 text-light">Authentication key needed to continue</h6>
<small>Please provide it below:</small>
<form class="form-inline" method="post" action="{{urlpath}}/admin">
@@ -17,7 +17,7 @@
{{#if redirect}}
<input type="hidden" id="redirect" name="redirect" value="/{{redirect}}">
{{/if}}
- <button type="submit" class="btn btn-primary">Enter</button>
+ <button type="submit" class="btn btn-primary mt-2">Enter</button>
</form>
</div>
</div>
diff --git a/src/static/templates/admin/organizations.hbs b/src/static/templates/admin/organizations.hbs
index 7ac2b6ba..f0563cec 100644
--- a/src/static/templates/admin/organizations.hbs
+++ b/src/static/templates/admin/organizations.hbs
@@ -1,5 +1,5 @@
<main class="container-xl">
- <div id="organizations-block" class="my-3 p-3 bg-white rounded shadow">
+ <div id="organizations-block" class="my-3 p-3 rounded shadow">
<h6 class="border-bottom pb-2 mb-3">Organizations</h6>
<div class="table-responsive-xl small">
<table id="orgs-table" class="table table-sm table-striped table-hover">
@@ -59,7 +59,7 @@
</main>
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
-<script src="{{urlpath}}/vw_static/jquery-3.6.4.slim.js"></script>
+<script src="{{urlpath}}/vw_static/jquery-3.7.0.slim.js"></script>
<script src="{{urlpath}}/vw_static/datatables.js"></script>
<script src="{{urlpath}}/vw_static/admin_organizations.js"></script>
<script src="{{urlpath}}/vw_static/jdenticon.js"></script>
diff --git a/src/static/templates/admin/settings.hbs b/src/static/templates/admin/settings.hbs
index b8ee5f4b..fb066cb4 100644
--- a/src/static/templates/admin/settings.hbs
+++ b/src/static/templates/admin/settings.hbs
@@ -17,7 +17,7 @@
<form class="form needs-validation" id="config-form" novalidate>
{{#each page_data.config}}
{{#if groupdoc}}
- <div class="card bg-light mb-3">
+ <div class="card mb-3">
<button id="b_{{group}}" type="button" class="card-header text-start btn btn-link text-decoration-none" aria-expanded="false" aria-controls="g_{{group}}" data-bs-toggle="collapse" data-bs-target="#g_{{group}}">{{groupdoc}}</button>
<div id="g_{{group}}" class="card-body collapse">
{{#each elements}}
@@ -64,7 +64,7 @@
{{/if}}
{{/each}}
- <div class="card bg-light mb-3">
+ <div class="card mb-3">
<button id="b_readonly" type="button" class="card-header text-start btn btn-link text-decoration-none" aria-expanded="false" aria-controls="g_readonly"
data-bs-toggle="collapse" data-bs-target="#g_readonly">Read-Only Config</button>
<div id="g_readonly" class="card-body collapse">
@@ -119,7 +119,7 @@
</div>
{{#if page_data.can_backup}}
- <div class="card bg-light mb-3">
+ <div class="card mb-3">
<button id="b_database" type="button" class="card-header text-start btn btn-link text-decoration-none" aria-expanded="false" aria-controls="g_database"
data-bs-toggle="collapse" data-bs-target="#g_database">Backup Database</button>
<div id="g_database" class="card-body collapse">
diff --git a/src/static/templates/admin/users.hbs b/src/static/templates/admin/users.hbs
index 637dfb22..d8b7289f 100644
--- a/src/static/templates/admin/users.hbs
+++ b/src/static/templates/admin/users.hbs
@@ -1,5 +1,5 @@
<main class="container-xl">
- <div id="users-block" class="my-3 p-3 bg-white rounded shadow">
+ <div id="users-block" class="my-3 p-3 rounded shadow">
<h6 class="border-bottom pb-2 mb-3">Registered Users</h6>
<div class="table-responsive-xl small">
<table id="users-table" class="table table-sm table-striped table-hover">
@@ -30,7 +30,7 @@
<span class="badge bg-success me-2" title="2FA is enabled">2FA</span>
{{/if}}
{{#case _Status 1}}
- <span class="badge bg-warning me-2" title="User is invited">Invited</span>
+ <span class="badge bg-warning text-dark me-2" title="User is invited">Invited</span>
{{/case}}
{{#if EmailVerified}}
<span class="badge bg-success me-2" title="Email has been verified">Verified</span>
@@ -140,7 +140,7 @@
</main>
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
-<script src="{{urlpath}}/vw_static/jquery-3.6.4.slim.js"></script>
+<script src="{{urlpath}}/vw_static/jquery-3.7.0.slim.js"></script>
<script src="{{urlpath}}/vw_static/datatables.js"></script>
<script src="{{urlpath}}/vw_static/admin_users.js"></script>
<script src="{{urlpath}}/vw_static/jdenticon.js"></script>