|
- /**
- * --------------------------------------------------------------------------
- * Bootstrap (v5.1.3): util/index.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-
- define([
- "jquery",
- 'domReady!'
- ], function() {
- 'use strict';
-
- const MAX_UID = 1000000
- const MILLISECONDS_MULTIPLIER = 1000
- const TRANSITION_END = 'transitionend'
-
- // Shoutout AngusCroll (https://goo.gl/pxwQGp)
- const toType = obj => {
- if (obj === null || obj === undefined) {
- return `${obj}`
- }
-
- return {}.toString.call(obj).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 getSelector = element => {
- let selector = element.getAttribute('data-bs-target')
-
- if (!selector || selector === '#') {
- let hrefAttr = 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 (!hrefAttr || (!hrefAttr.includes('#') && !hrefAttr.startsWith('.'))) {
- return null
- }
-
- // Just in case some CMS puts out a full URL with the anchor appended
- if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
- hrefAttr = `#${hrefAttr.split('#')[1]}`
- }
-
- selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null
- }
-
- return selector
- }
-
- const getSelectorFromElement = element => {
- const selector = getSelector(element)
-
- if (selector) {
- return document.querySelector(selector) ? selector : null
- }
-
- return null
- }
-
- const getElementFromSelector = element => {
- const selector = getSelector(element)
-
- return selector ? document.querySelector(selector) : null
- }
-
- 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 = obj => {
- if (!obj || typeof obj !== 'object') {
- return false
- }
-
- if (typeof obj.jquery !== 'undefined') {
- obj = obj[0]
- }
-
- return typeof obj.nodeType !== 'undefined'
- }
-
- const getElement = obj => {
- if (isElement(obj)) { // it's a jQuery object or a node element
- return obj.jquery ? obj[0] : obj
- }
-
- if (typeof obj === 'string' && obj.length > 0) {
- return document.querySelector(obj)
- }
-
- return null
- }
-
- const typeCheckConfig = (componentName, config, configTypes) => {
- Object.keys(configTypes).forEach(property => {
- const expectedTypes = configTypes[property]
- const value = config[property]
- const valueType = value && isElement(value) ? 'element' : toType(value)
-
- if (!new RegExp(expectedTypes).test(valueType)) {
- throw new TypeError(
- `${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`
- )
- }
- })
- }
-
- const isVisible = element => {
- if (!isElement(element) || element.getClientRects().length === 0) {
- return false
- }
-
- return getComputedStyle(element).getPropertyValue('visibility') === 'visible'
- }
-
- 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 => {
- // eslint-disable-next-line no-unused-expressions
- element.offsetHeight
- }
-
- const getjQuery = () => {
- const {jQuery} = window
-
- if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
- return 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', () => {
- DOMContentLoadedCallbacks.forEach(callback => 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 = callback => {
- if (typeof callback === 'function') {
- callback()
- }
- }
-
- 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) => {
- 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 list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]
- }
-
- const listLength = list.length
-
- index += shouldGetNext ? 1 : -1
-
- if (isCycleAllowed) {
- index = (index + listLength) % listLength
- }
-
- return list[Math.max(0, Math.min(index, listLength - 1))]
- }
-
- return {
- getElement,
- getUID,
- getSelectorFromElement,
- getElementFromSelector,
- getTransitionDurationFromElement,
- triggerTransitionEnd,
- isElement,
- typeCheckConfig,
- isVisible,
- isDisabled,
- findShadowRoot,
- noop,
- getNextActiveElement,
- reflow,
- getjQuery,
- onDOMContentLoaded,
- isRTL,
- defineJQueryPlugin,
- execute,
- executeAfterTransition
- };
- });
|