UNPKG

@coreui/coreui-pro

Version:

The most popular front-end framework for developing responsive, mobile-first projects on the web rewritten by the CoreUI Team

1,449 lines (1,365 loc) 455 kB
/*! * CoreUI v5.23.0 (https://coreui.io) * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people) * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core')) : typeof define === 'function' && define.amd ? define(['@popperjs/core'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.coreui = factory(global.Popper)); })(this, (function (Popper) { 'use strict'; function _interopNamespaceDefault(e) { const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); if (e) { for (const k in e) { if (k !== 'default') { const d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: () => e[k] }); } } } n.default = e; return Object.freeze(n); } const Popper__namespace = /*#__PURE__*/_interopNamespaceDefault(Popper); /** * -------------------------------------------------------------------------- * CoreUI dom/data.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's 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); } } }; /** * -------------------------------------------------------------------------- * CoreUI util/index.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's 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 = 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(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(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-coreui-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.call(...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))]; }; /** * -------------------------------------------------------------------------- * CoreUI dom/event-handler.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's 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', 'input', '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.coreui.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; } /** * -------------------------------------------------------------------------- * CoreUI dom/manipulator.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's 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-coreui-${normalizeDataKey(key)}`, value); }, removeDataAttribute(element, key) { element.removeAttribute(`data-coreui-${normalizeDataKey(key)}`); }, getDataAttributes(element) { if (!element) { return {}; } const attributes = {}; const coreuiKeys = Object.keys(element.dataset).filter(key => key.startsWith('coreui') && !key.startsWith('coreuiConfig')); for (const key of coreuiKeys) { let pureKey = key.replace(/^coreui/, ''); pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1); attributes[pureKey] = normalizeData(element.dataset[key]); } return attributes; }, getDataAttribute(element, key) { return normalizeData(element.getAttribute(`data-coreui-${normalizeDataKey(key)}`)); } }; /** * -------------------------------------------------------------------------- * CoreUI util/config.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's 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(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse return { ...this.constructor.Default, ...(typeof jsonConfig === 'object' ? jsonConfig : {}), ...(isElement(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(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}".`); } } } } /** * -------------------------------------------------------------------------- * CoreUI base-component.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This component is a modified version of the Bootstrap's base-component.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * Constants */ const VERSION = '5.23.0'; /** * 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; } } // Private _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 `coreui.${this.NAME}`; } static get EVENT_KEY() { return `.${this.DATA_KEY}`; } static eventName(name) { return `${name}${this.EVENT_KEY}`; } } /** * -------------------------------------------------------------------------- * CoreUI dom/selector-engine.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's dom/selector-engine.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const getSelector = element => { let selector = element.getAttribute('data-coreui-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 selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null; }; 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) : []; } }; /** * -------------------------------------------------------------------------- * CoreUI util/component-functions.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's 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-coreui-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](); }); }; /** * -------------------------------------------------------------------------- * CoreUI alert.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This component is a modified version of the Bootstrap's alert.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * Constants */ const NAME$t = 'alert'; const DATA_KEY$o = 'coreui.alert'; const EVENT_KEY$p = `.${DATA_KEY$o}`; const EVENT_CLOSE = `close${EVENT_KEY$p}`; const EVENT_CLOSED = `closed${EVENT_KEY$p}`; const CLASS_NAME_FADE$5 = 'fade'; const CLASS_NAME_SHOW$g = 'show'; /** * Class definition */ class Alert extends BaseComponent { // Getters static get NAME() { return NAME$t; } // Public close() { const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE); if (closeEvent.defaultPrevented) { return; } this._element.classList.remove(CLASS_NAME_SHOW$g); 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); /** * -------------------------------------------------------------------------- * CoreUI util/sanitizer.js * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) * * This is a modified version of the Bootstrap's 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: [], dd: [], div: [], dl: [], dt: [], 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 */ 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; } /** * -------------------------------------------------------------------------- * CoreUI PRO autocomplete.js * License (https://coreui.io/pro/license/) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$s = 'autocomplete'; const DATA_KEY$n = 'coreui.autocomplete'; const EVENT_KEY$o = `.${DATA_KEY$n}`; const DATA_API_KEY$j = '.data-api'; const ARROW_UP_KEY$6 = 'ArrowUp'; const ARROW_DOWN_KEY$6 = 'ArrowDown'; const BACKSPACE_KEY$2 = 'Backspace'; const DELETE_KEY$1 = 'Delete'; const ENTER_KEY$4 = 'Enter'; const ESCAPE_KEY$6 = 'Escape'; const TAB_KEY$6 = 'Tab'; const RIGHT_MOUSE_BUTTON$5 = 2; // MouseEvent.button value for the secondary button, usually the right button const EVENT_BLUR$1 = `blur${EVENT_KEY$o}`; const EVENT_CHANGED$1 = `changed${EVENT_KEY$o}`; const EVENT_CLICK$6 = `click${EVENT_KEY$o}`; const EVENT_HIDE$c = `hide${EVENT_KEY$o}`; const EVENT_HIDDEN$c = `hidden${EVENT_KEY$o}`; const EVENT_INPUT$4 = `input${EVENT_KEY$o}`; const EVENT_KEYDOWN$8 = `keydown${EVENT_KEY$o}`; const EVENT_KEYUP$1 = `keyup${EVENT_KEY$o}`; const EVENT_SHOW$c = `show${EVENT_KEY$o}`; const EVENT_SHOWN$c = `shown${EVENT_KEY$o}`; const EVENT_CLICK_DATA_API$h = `click${EVENT_KEY$o}${DATA_API_KEY$j}`; const EVENT_KEYUP_DATA_API$5 = `keyup${EVENT_KEY$o}${DATA_API_KEY$j}`; const EVENT_LOAD_DATA_API$f = `load${EVENT_KEY$o}${DATA_API_KEY$j}`; const CLASS_NAME_AUTOCOMPLETE = 'autocomplete'; const CLASS_NAME_BUTTONS = 'autocomplete-buttons'; const CLASS_NAME_CLEANER$3 = 'autocomplete-cleaner'; const CLASS_NAME_DISABLED$5 = 'disabled'; const CLASS_NAME_DROPDOWN$2 = 'autocomplete-dropdown'; const CLASS_NAME_INDICATOR$2 = 'autocomplete-indicator'; const CLASS_NAME_INPUT$2 = 'autocomplete-input'; const CLASS_NAME_INPUT_HINT = 'autocomplete-input-hint'; const CLASS_NAME_INPUT_GROUP$3 = 'autocomplete-input-group'; const CLASS_NAME_LABEL$1 = 'label'; const CLASS_NAME_OPTGROUP$1 = 'autocomplete-optgroup'; const CLASS_NAME_OPTGROUP_LABEL$1 = 'autocomplete-optgroup-label'; const CLASS_NAME_OPTION$1 = 'autocomplete-option'; const CLASS_NAME_OPTIONS$1 = 'autocomplete-options'; const CLASS_NAME_OPTIONS_EMPTY$1 = 'autocomplete-options-empty'; const CLASS_NAME_SELECTED$2 = 'selected'; const CLASS_NAME_SHOW$f = 'show'; const SELECTOR_DATA_TOGGLE$h = '[data-coreui-toggle="autocomplete"]:not(.disabled)'; const SELECTOR_DATA_TOGGLE_SHOWN$4 = `.autocomplete:not(.disabled).${CLASS_NAME_SHOW$f}`; const SELECTOR_INDICATOR = '.autocomplete-indicator'; const SELECTOR_OPTGROUP$1 = '.autocomplete-optgroup'; const SELECTOR_OPTION$1 = '.autocomplete-option'; const SELECTOR_OPTIONS$1 = '.autocomplete-options'; const SELECTOR_OPTIONS_EMPTY$1 = '.autocomplete-options-empty'; const SELECTOR_VISIBLE_ITEMS$2 = '.autocomplete-options .autocomplete-option:not(.disabled):not(:disabled)'; const Default$p = { allowList: DefaultAllowlist, allowOnlyDefinedOptions: false, ariaCleanerLabel: 'Clear selection', ariaIndicatorLabel: 'Toggle visibility of options menu', cleaner: false, clearSearchOnSelect: true, container: false, disabled: false, highlightOptionsOnSearch: false, id: null, indicator: false, invalid: false, name: null, options: false, optionsGroupsTemplate: null, optionsMaxHeight: 'auto', optionsTemplate: null, placeholder: null, required: false, sanitize: true, sanitizeFn: null, search: null, searchNoResultsLabel: false, showHints: false, valid: false, value: null }; const DefaultType$p = { allowList: 'object', allowOnlyDefinedOptions: 'boolean', ariaCleanerLabel: 'string', ariaIndicatorLabel: 'string', cleaner: 'boolean', clearSearchOnSelect: 'boolean', container: '(string|element|boolean)', disabled: 'boolean', highlightOptionsOnSearch: 'boolean', id: '(string|null)', indicator: 'boolean', invalid: 'boolean', name: '(string|null)', options: '(array|null)', optionsGroupsTemplate: '(function|null)', optionsMaxHeight: '(number|string)', optionsTemplate: '(function|null)', placeholder: '(string|null)', required: 'boolean', sanitize: 'boolean', sanitizeFn: '(null|function)', search: '(array|string|null)', searchNoResultsLabel: 'boolean|string', showHints: 'boolean', valid: 'boolean', value: '(number|string|null)' }; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Autocomplete extends BaseComponent { constructor(element, config) { var _this$_config$id; super(element, config); this._uniqueId = (_this$_config$id = this._config.id) != null ? _this$_config$id : getUID(`${this.constructor.NAME}`); this._indicatorElement = null; this._inputElement = null; this._inputHintElement = null; this._togglerElement = null; this._optionsElement = null; this._menu = null; this._selected = []; this._options = this._getOptionsFromConfig(); this._popper = null; this._search = ''; this._createAutocomplete(); this._addEventListeners(); Data.set(this._element, DATA_KEY$n, this); } // Getters static get Default() { return Default$p; } static get DefaultType() { return DefaultType$p; } static get NAME() { return NAME$s; } // Public toggle() { return this._isShown() ? this.hide() : this.show(); } show() { if (this._config.disabled || this._isShown()) { return; } if (!this._config.searchNoResultsLabel && this._flattenOptions().filter(option => option.label.toLowerCase().includes(this._search.toLowerCase())).length === 0) { return; } EventHandler.trigger(this._element, EVENT_SHOW$c); this._element.classList.add(CLASS_NAME_SHOW$f); this._inputElement.setAttribute('aria-expanded', 'true'); if (this._config.container) { this._menu.style.minWidth = `${this._element.offsetWidth}px`; this._menu.classList.add(CLASS_NAME_SHOW$f); } EventHandler.trigger(this._element, EVENT_SHOWN$c); this._createPopper(); } hide() { EventHandler.trigger(this._element, EVENT_HIDE$c); if (this._popper) { this._popper.destroy(); } this._element.classList.remove(CLASS_NAME_SHOW$f); this._inputElement.setAttribute('aria-expanded', 'false'); if (this._config.container) { this._menu.classList.remove(CLASS_NAME_SHOW$f); } if (this._inputHintElement) { this._inputHintElement.value = ''; } EventHandler.trigger(this._element, EVENT_HIDDEN$c); } dispose() { if (this._popper) { this._popper.destroy(); } super.dispose(); } clear() { this.deselectAll(); this.search(''); this._filterOptionsList(); this._inputElement.value = ''; EventHandler.trigger(this._element, EVENT_CHANGED$1, { value: this._selected }); } search(label) { this._search = label.length > 0 ? label.toLowerCase() : ''; if (!this._isExternalSearch()) { this._filterOptionsList(); } EventHandler.trigger(this._element, EVENT_INPUT$4, { value: label }); } update(config) { if (config.value) { this.deselectAll(); } this._config = { ...this._config, ...this._configAfterMerge(config) }; this._options = this._getOptionsFromConfig(); this._optionsElement.innerHTML = ''; this._createOptions(this._optionsElement, this._options); } deselectAll(options = this._selected) { if (this._selected.length === 0) { return; } for (const option of options) { if (option.disabled) { continue; } if (Array.isArray(option.options)) { this.deselectAll(option.options); continue; } this._deselectOption(option.value); this._updateCleaner(); } } // Helpers _flattenOptions(options = this._options, flat = []) { for (const opt of options) { if (opt && Array.isArray(opt.options)) { this._flattenOptions(opt.options, flat); continue; } flat.push(opt); } return flat; } _getClassNames() { return this._element.classList.value.split(' '); } _highlightOption(label) { const regex = new RegExp(this._search, 'gi'); return label.replace(regex, string => `<strong>${string}</strong>`); } _isExternalSearch() { return Array.isArray(this._config.search) && this._config.search.includes('external'); } _isGlobalSearch() { return Array.isArray(this._config.search) && this._config.search.includes('global'); } _isVisible(element) { const style = window.getComputedStyle(element); return style.display !== 'none'; } _isShown() { return this._element.classList.contains(CLASS_NAME_SHOW$f); } // Private _addEventListeners() { EventHandler.on(this._element, EVENT_CLICK$6, event => { if (!this._config.disabled && !event.target.closest(SELECTOR_INDICATOR)) { this.show(); } }); EventHandler.on(this._element, EVENT_KEYDOWN$8, event => { if (event.key === ESCAPE_KEY$6) { this.hide(); if (this._config.allowOnlyDefinedOptions && this._selected.length === 0) { this.search(''); this._inputElement.value = ''; } return; } if (this._isGlobalSearch() && (event.key.length === 1 || event.key === BACKSPACE_KEY$2 || event.key === DELETE_KEY$1)) { this._inputElement.focus(); } }); EventHandler.on(this._menu, EVENT_KEYDOWN$8, event => { if (this._isGlobalSearch() && (event.key.length === 1 || event.key === BACKSPACE_KEY$2 || event.key === DELETE_KEY$1)) { this._inputElement.focus(); } }); EventHandler.on(this._togglerElement, EVENT_KEYDOWN$8, event => { if (!this._isShown() && (event.key === ENTER_KEY$4 || event.key === ARROW_DOWN_KEY$6)) { event.preventDefault(); this.show(); return; } if (this._isShown() && event.key === ARROW_DOWN_KEY$6) { event.preventDefault(); this._selectMenuItem(event); } }); EventHandler.on(this._indicatorElement, EVENT_CLICK$6, event => { event.preventDefault(); this.toggle(); }); EventHandler.on(this._inputElement, EVENT_BLUR$1, () => { const options = this._flattenOptions().filter(option => option.label.toLowerCase().startsWith(this._inputElement.value.toLowerCase())); if (this._config.allowOnlyDefinedOptions && this._selected.length === 0 && options.length === 0) { this.clear(); } }); EventHandler.on(this._inputElement, EVENT_KEYDOWN$8, event => { if (!this._isShown() && event.key !== TAB_KEY$6) { this.show(); } if (event.key === ARROW_DOWN_KEY$6 && this._inputElement.value.length === this._inputElement.selectionStart) { this._selectMenuItem(event); return; } if (event.key === TAB_KEY$6 && this._config.showHints && this._inputElement.value.length > 0) { if (this._inputHintElement.value) { event.preventDefault(); event.stopPropagation(); } const options = this._flattenOptions().filter(option => option.label.toLowerCase().startsWith(this._inputElement.value.toLowerCase())); if (options.length > 0) { this._selectOption(options[0]); } } if (event.key === ENTER_KEY$4) { event.preventDefault(); event.stopPropagation(); if (this._inputElement.value.length === 0) { return; } const options = this._flattenOptions().filter(option => option.label.toLowerCase() === this._inputElement.value.toLowerCase()); if (options.length > 0) { this._selectOption(options[0]); } if (options.length === 0 && !this._config.allowOnlyDefinedOptions) { EventHandler.trigger(this._element, EVENT_CHANGED$1, { value: this._inputElement.value }); this.hide(); if (this._config.clearSearchOnSelect) { this.search(''); } } } }); EventHandler.on(this._inputElement, EVENT_KEYUP$1, event => { if (event.key.length === 1 || event.key === BACKSPACE_KEY$2 || event.key === DELETE_KEY$1) { const { value } = event.target; this.search(value); if (this._config.showHints) { const options = value ? this._flattenOptions().filter(option => option.label.toLowerCase().startsWith(value.toLowerCase())) : []; this._inputHintElement.value = options.length > 0 ? `${value}${options[0].label.slice(value.length)}` : ''; } if (this._selected.length > 0) { this.deselectAll(); EventHandler.trigger(this._element, EVENT_CHANGED$1, { value: this._selected }); } } }); EventHandler.on(this._optionsElement, EVENT_CLICK$6, event => { event.preventDefault(); event.stopPropagation(); this._onOptionsClick(event.target); }); EventHandler.on(this._cleanerElement, EVENT_CLICK$6, event => { if (!this._config.disabled) { event.preventDefault(); event.stopPropagation(); this.clear(); } }); EventHandler.on(this._cleanerElement, EVENT_KEYDOWN$8, event => { if (!this._config.disabled && event.key === ENTER_KEY$4) { event.preventDefault(); event.stopPropagation(); this.clear(); } }); EventHandler.on(this._optionsElement, EVENT_KEYDOWN$8, event => { if (event.key === ENTER_KEY$