1
0
Fork 0

Adding upstream version 5.3.0+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-08 17:47:43 +02:00
parent 5d8756ab77
commit d4ccd9dae1
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
605 changed files with 15320 additions and 9495 deletions

View file

@ -1,14 +1,14 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): alert.js
* Bootstrap alert.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { defineJQueryPlugin } from './util/index'
import EventHandler from './dom/event-handler'
import BaseComponent from './base-component'
import { enableDismissTrigger } from './util/component-functions'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import { enableDismissTrigger } from './util/component-functions.js'
import { defineJQueryPlugin } from './util/index.js'
/**
* Constants

View file

@ -1,20 +1,20 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): base-component.js
* Bootstrap base-component.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import Data from './dom/data'
import { executeAfterTransition, getElement } from './util/index'
import EventHandler from './dom/event-handler'
import Config from './util/config'
import Data from './dom/data.js'
import EventHandler from './dom/event-handler.js'
import Config from './util/config.js'
import { executeAfterTransition, getElement } from './util/index.js'
/**
* Constants
*/
const VERSION = '5.2.3'
const VERSION = '5.3.0'
/**
* Class definition

View file

@ -1,13 +1,13 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): button.js
* Bootstrap button.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { defineJQueryPlugin } from './util/index'
import EventHandler from './dom/event-handler'
import BaseComponent from './base-component'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import { defineJQueryPlugin } from './util/index.js'
/**
* Constants

View file

@ -1,24 +1,23 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): carousel.js
* Bootstrap carousel.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import Manipulator from './dom/manipulator.js'
import SelectorEngine from './dom/selector-engine.js'
import {
defineJQueryPlugin,
getElementFromSelector,
getNextActiveElement,
isRTL,
isVisible,
reflow,
triggerTransitionEnd
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selector-engine'
import Swipe from './util/swipe'
import BaseComponent from './base-component'
} from './util/index.js'
import Swipe from './util/swipe.js'
/**
* Constants
@ -330,7 +329,7 @@ class Carousel extends BaseComponent {
if (!activeElement || !nextElement) {
// Some weirdness is happening, so we bail
// todo: change tests that use empty divs to avoid this check
// TODO: change tests that use empty divs to avoid this check
return
}
@ -431,7 +430,7 @@ class Carousel extends BaseComponent {
*/
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {
const target = getElementFromSelector(this)
const target = SelectorEngine.getElementFromSelector(this)
if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
return

View file

@ -1,20 +1,18 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): collapse.js
* Bootstrap collapse.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import {
defineJQueryPlugin,
getElement,
getElementFromSelector,
getSelectorFromElement,
reflow
} from './util/index'
import EventHandler from './dom/event-handler'
import SelectorEngine from './dom/selector-engine'
import BaseComponent from './base-component'
} from './util/index.js'
/**
* Constants
@ -68,7 +66,7 @@ class Collapse extends BaseComponent {
const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)
for (const elem of toggleList) {
const selector = getSelectorFromElement(elem)
const selector = SelectorEngine.getSelectorFromElement(elem)
const filterElement = SelectorEngine.find(selector)
.filter(foundElement => foundElement === this._element)
@ -185,7 +183,7 @@ class Collapse extends BaseComponent {
this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)
for (const trigger of this._triggerArray) {
const element = getElementFromSelector(trigger)
const element = SelectorEngine.getElementFromSelector(trigger)
if (element && !this._isShown(element)) {
this._addAriaAndCollapsedClass([trigger], false)
@ -229,7 +227,7 @@ class Collapse extends BaseComponent {
const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)
for (const element of children) {
const selected = getElementFromSelector(element)
const selected = SelectorEngine.getElementFromSelector(element)
if (selected) {
this._addAriaAndCollapsedClass([element], this._isShown(selected))
@ -285,10 +283,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
event.preventDefault()
}
const selector = getSelectorFromElement(this)
const selectorElements = SelectorEngine.find(selector)
for (const element of selectorElements) {
for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {
Collapse.getOrCreateInstance(element, { toggle: false }).toggle()
}
})

View file

@ -1,6 +1,6 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): dom/data.js
* Bootstrap dom/data.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/

View file

@ -1,11 +1,11 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): dom/event-handler.js
* Bootstrap dom/event-handler.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { getjQuery } from '../util/index'
import { getjQuery } from '../util/index.js'
/**
* Constants
@ -128,7 +128,7 @@ function findHandler(events, callable, delegationSelector = null) {
function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
const isDelegated = typeof handler === 'string'
// todo: tooltip passes `false` instead of selector, so we need to check
// TODO: tooltip passes `false` instead of selector, so we need to check
const callable = isDelegated ? delegationFunction : (handler || delegationFunction)
let typeEvent = getTypeEvent(originalTypeEvent)
@ -198,9 +198,8 @@ function removeHandler(element, events, typeEvent, handler, delegationSelector)
function removeNamespacedHandlers(element, events, typeEvent, namespace) {
const storeElementEvent = events[typeEvent] || {}
for (const handlerKey of Object.keys(storeElementEvent)) {
for (const [handlerKey, event] of Object.entries(storeElementEvent)) {
if (handlerKey.includes(namespace)) {
const event = storeElementEvent[handlerKey]
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
}
}
@ -248,11 +247,10 @@ const EventHandler = {
}
}
for (const keyHandlers of Object.keys(storeElementEvent)) {
for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {
const handlerKey = keyHandlers.replace(stripUidRegex, '')
if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
const event = storeElementEvent[keyHandlers]
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
}
}
@ -281,8 +279,7 @@ const EventHandler = {
defaultPrevented = jQueryEvent.isDefaultPrevented()
}
let evt = new Event(event, { bubbles, cancelable: true })
evt = hydrateObj(evt, args)
const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)
if (defaultPrevented) {
evt.preventDefault()
@ -300,8 +297,8 @@ const EventHandler = {
}
}
function hydrateObj(obj, meta) {
for (const [key, value] of Object.entries(meta || {})) {
function hydrateObj(obj, meta = {}) {
for (const [key, value] of Object.entries(meta)) {
try {
obj[key] = value
} catch {

View file

@ -1,6 +1,6 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): dom/manipulator.js
* Bootstrap dom/manipulator.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/

View file

@ -1,15 +1,36 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): dom/selector-engine.js
* Bootstrap dom/selector-engine.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { isDisabled, isVisible } from '../util/index'
import { isDisabled, isVisible, parseSelector } from '../util/index.js'
/**
* Constants
*/
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) {
@ -77,6 +98,28 @@ const SelectorEngine = {
].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) : []
}
}

View file

@ -1,13 +1,18 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): dropdown.js
* Bootstrap dropdown.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import * as Popper from '@popperjs/core'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import Manipulator from './dom/manipulator.js'
import SelectorEngine from './dom/selector-engine.js'
import {
defineJQueryPlugin,
execute,
getElement,
getNextActiveElement,
isDisabled,
@ -15,11 +20,7 @@ import {
isRTL,
isVisible,
noop
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selector-engine'
import BaseComponent from './base-component'
} from './util/index.js'
/**
* Constants
@ -95,7 +96,7 @@ class Dropdown extends BaseComponent {
this._popper = null
this._parent = this._element.parentNode // dropdown wrapper
// todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.2/forms/input-group/
// 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)
@ -310,7 +311,7 @@ class Dropdown extends BaseComponent {
// 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
Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove
defaultBsPopperConfig.modifiers = [{
name: 'applyStyles',
enabled: false
@ -319,7 +320,7 @@ class Dropdown extends BaseComponent {
return {
...defaultBsPopperConfig,
...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
...execute(this._config.popperConfig, [defaultBsPopperConfig])
}
}
@ -408,7 +409,7 @@ class Dropdown extends BaseComponent {
event.preventDefault()
// todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.2/forms/input-group/
// TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?
this :
(SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||

View file

@ -1,18 +1,18 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): modal.js
* Bootstrap modal.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { defineJQueryPlugin, getElementFromSelector, isRTL, isVisible, reflow } from './util/index'
import EventHandler from './dom/event-handler'
import SelectorEngine from './dom/selector-engine'
import ScrollBarHelper from './util/scrollbar'
import BaseComponent from './base-component'
import Backdrop from './util/backdrop'
import FocusTrap from './util/focustrap'
import { enableDismissTrigger } from './util/component-functions'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import Backdrop from './util/backdrop.js'
import { enableDismissTrigger } from './util/component-functions.js'
import FocusTrap from './util/focustrap.js'
import { defineJQueryPlugin, isRTL, isVisible, reflow } from './util/index.js'
import ScrollBarHelper from './util/scrollbar.js'
/**
* Constants
@ -139,12 +139,12 @@ class Modal extends BaseComponent {
}
dispose() {
for (const htmlElement of [window, this._dialog]) {
EventHandler.off(htmlElement, EVENT_KEY)
}
EventHandler.off(window, EVENT_KEY)
EventHandler.off(this._dialog, EVENT_KEY)
this._backdrop.dispose()
this._focustrap.deactivate()
super.dispose()
}
@ -208,7 +208,6 @@ class Modal extends BaseComponent {
}
if (this._config.keyboard) {
event.preventDefault()
this.hide()
return
}
@ -336,7 +335,7 @@ class Modal extends BaseComponent {
*/
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
const target = getElementFromSelector(this)
const target = SelectorEngine.getElementFromSelector(this)
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault()

View file

@ -1,23 +1,22 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): offcanvas.js
* Bootstrap offcanvas.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import Backdrop from './util/backdrop.js'
import { enableDismissTrigger } from './util/component-functions.js'
import FocusTrap from './util/focustrap.js'
import {
defineJQueryPlugin,
getElementFromSelector,
isDisabled,
isVisible
} from './util/index'
import ScrollBarHelper from './util/scrollbar'
import EventHandler from './dom/event-handler'
import BaseComponent from './base-component'
import SelectorEngine from './dom/selector-engine'
import Backdrop from './util/backdrop'
import FocusTrap from './util/focustrap'
import { enableDismissTrigger } from './util/component-functions'
} from './util/index.js'
import ScrollBarHelper from './util/scrollbar.js'
/**
* Constants
@ -199,12 +198,12 @@ class Offcanvas extends BaseComponent {
return
}
if (!this._config.keyboard) {
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
if (this._config.keyboard) {
this.hide()
return
}
this.hide()
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
})
}
@ -231,7 +230,7 @@ class Offcanvas extends BaseComponent {
*/
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
const target = getElementFromSelector(this)
const target = SelectorEngine.getElementFromSelector(this)
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault()

View file

@ -1,12 +1,12 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): popover.js
* Bootstrap popover.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { defineJQueryPlugin } from './util/index'
import Tooltip from './tooltip'
import Tooltip from './tooltip.js'
import { defineJQueryPlugin } from './util/index.js'
/**
* Constants

View file

@ -1,14 +1,14 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): scrollspy.js
* Bootstrap scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { defineJQueryPlugin, getElement, isDisabled, isVisible } from './util/index'
import EventHandler from './dom/event-handler'
import SelectorEngine from './dom/selector-engine'
import BaseComponent from './base-component'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import { defineJQueryPlugin, getElement, isDisabled, isVisible } from './util/index.js'
/**
* Constants
@ -208,11 +208,11 @@ class ScrollSpy extends BaseComponent {
continue
}
const observableSection = SelectorEngine.findOne(anchor.hash, this._element)
const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)
// ensure that the observableSection exists & is visible
if (isVisible(observableSection)) {
this._targetLinks.set(anchor.hash, anchor)
this._targetLinks.set(decodeURI(anchor.hash), anchor)
this._observableSections.set(anchor.hash, observableSection)
}
}

View file

@ -1,14 +1,14 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): tab.js
* Bootstrap tab.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { defineJQueryPlugin, getElementFromSelector, getNextActiveElement, isDisabled } from './util/index'
import EventHandler from './dom/event-handler'
import SelectorEngine from './dom/selector-engine'
import BaseComponent from './base-component'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'
/**
* Constants
@ -43,7 +43,7 @@ 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:v6: could be only `tab`
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"]`
@ -59,7 +59,7 @@ class Tab extends BaseComponent {
if (!this._parent) {
return
// todo: should Throw exception on v6
// TODO: should throw exception in v6
// throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
}
@ -106,7 +106,7 @@ class Tab extends BaseComponent {
element.classList.add(CLASS_NAME_ACTIVE)
this._activate(getElementFromSelector(element)) // Search and activate/show the proper section
this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section
const complete = () => {
if (element.getAttribute('role') !== 'tab') {
@ -133,7 +133,7 @@ class Tab extends BaseComponent {
element.classList.remove(CLASS_NAME_ACTIVE)
element.blur()
this._deactivate(getElementFromSelector(element)) // Search and deactivate the shown section too
this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too
const complete = () => {
if (element.getAttribute('role') !== 'tab') {
@ -203,7 +203,7 @@ class Tab extends BaseComponent {
}
_setInitialAttributesOnTargetPanel(child) {
const target = getElementFromSelector(child)
const target = SelectorEngine.getElementFromSelector(child)
if (!target) {
return
@ -212,7 +212,7 @@ class Tab extends BaseComponent {
this._setAttributeIfNotExists(target, 'role', 'tabpanel')
if (child.id) {
this._setAttributeIfNotExists(target, 'aria-labelledby', `#${child.id}`)
this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)
}
}

View file

@ -1,14 +1,14 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): toast.js
* Bootstrap toast.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { defineJQueryPlugin, reflow } from './util/index'
import EventHandler from './dom/event-handler'
import BaseComponent from './base-component'
import { enableDismissTrigger } from './util/component-functions'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import { enableDismissTrigger } from './util/component-functions.js'
import { defineJQueryPlugin, reflow } from './util/index.js'
/**
* Constants

View file

@ -1,17 +1,17 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): tooltip.js
* Bootstrap tooltip.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import * as Popper from '@popperjs/core'
import { defineJQueryPlugin, findShadowRoot, getElement, getUID, isRTL, noop } from './util/index'
import { DefaultAllowlist } from './util/sanitizer'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import BaseComponent from './base-component'
import TemplateFactory from './util/template-factory'
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import Manipulator from './dom/manipulator.js'
import { defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop } from './util/index.js'
import { DefaultAllowlist } from './util/sanitizer.js'
import TemplateFactory from './util/template-factory.js'
/**
* Constants
@ -62,7 +62,7 @@ const Default = {
delay: 0,
fallbackPlacements: ['top', 'right', 'bottom', 'left'],
html: false,
offset: [0, 0],
offset: [0, 6],
placement: 'top',
popperConfig: null,
sanitize: true,
@ -197,7 +197,7 @@ class Tooltip extends BaseComponent {
return
}
// todo v6 remove this OR make it optional
// TODO: v6 remove this or make it optional
this._disposePopper()
const tip = this._getTipElement()
@ -302,13 +302,13 @@ class Tooltip extends BaseComponent {
_createTipElement(content) {
const tip = this._getTemplateFactory(content).toHtml()
// todo: remove this check on v6
// TODO: remove this check in v6
if (!tip) {
return null
}
tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)
// todo: on v6 the following can be achieved with CSS only
// 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()
@ -370,9 +370,7 @@ class Tooltip extends BaseComponent {
}
_createPopper(tip) {
const placement = typeof this._config.placement === 'function' ?
this._config.placement.call(this, tip, this._element) :
this._config.placement
const placement = execute(this._config.placement, [this, tip, this._element])
const attachment = AttachmentMap[placement.toUpperCase()]
return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))
}
@ -392,7 +390,7 @@ class Tooltip extends BaseComponent {
}
_resolvePossibleFunction(arg) {
return typeof arg === 'function' ? arg.call(this._element) : arg
return execute(arg, [this._element])
}
_getPopperConfig(attachment) {
@ -438,7 +436,7 @@ class Tooltip extends BaseComponent {
return {
...defaultBsPopperConfig,
...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
...execute(this._config.popperConfig, [defaultBsPopperConfig])
}
}
@ -579,9 +577,9 @@ class Tooltip extends BaseComponent {
_getDelegateConfig() {
const config = {}
for (const key in this._config) {
if (this.constructor.Default[key] !== this._config[key]) {
config[key] = this._config[key]
for (const [key, value] of Object.entries(this._config)) {
if (this.constructor.Default[key] !== value) {
config[key] = value
}
}

View file

@ -1,13 +1,13 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/backdrop.js
* Bootstrap util/backdrop.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import EventHandler from '../dom/event-handler'
import { execute, executeAfterTransition, getElement, reflow } from './index'
import Config from './config'
import EventHandler from '../dom/event-handler.js'
import Config from './config.js'
import { execute, executeAfterTransition, getElement, reflow } from './index.js'
/**
* Constants

View file

@ -1,12 +1,13 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/component-functions.js
* Bootstrap util/component-functions.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import EventHandler from '../dom/event-handler'
import { getElementFromSelector, isDisabled } from './index'
import EventHandler from '../dom/event-handler.js'
import SelectorEngine from '../dom/selector-engine.js'
import { isDisabled } from './index.js'
const enableDismissTrigger = (component, method = 'hide') => {
const clickEvent = `click.dismiss${component.EVENT_KEY}`
@ -21,7 +22,7 @@ const enableDismissTrigger = (component, method = 'hide') => {
return
}
const target = getElementFromSelector(this) || this.closest(`.${name}`)
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

View file

@ -1,12 +1,12 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/config.js
* Bootstrap util/config.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { isElement, toType } from './index'
import Manipulator from '../dom/manipulator'
import Manipulator from '../dom/manipulator.js'
import { isElement, toType } from './index.js'
/**
* Class definition
@ -49,8 +49,7 @@ class Config {
}
_typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
for (const property of Object.keys(configTypes)) {
const expectedTypes = configTypes[property]
for (const [property, expectedTypes] of Object.entries(configTypes)) {
const value = config[property]
const valueType = isElement(value) ? 'element' : toType(value)

View file

@ -1,13 +1,13 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/focustrap.js
* Bootstrap util/focustrap.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import EventHandler from '../dom/event-handler'
import SelectorEngine from '../dom/selector-engine'
import Config from './config'
import EventHandler from '../dom/event-handler.js'
import SelectorEngine from '../dom/selector-engine.js'
import Config from './config.js'
/**
* Constants

View file

@ -1,6 +1,6 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/index.js
* Bootstrap util/index.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
@ -9,6 +9,20 @@ const MAX_UID = 1_000_000
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) {
@ -30,47 +44,6 @@ const getUID = prefix => {
return prefix
}
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 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
@ -117,7 +90,7 @@ const getElement = object => {
}
if (typeof object === 'string' && object.length > 0) {
return document.querySelector(object)
return document.querySelector(parseSelector(object))
}
return null
@ -249,10 +222,8 @@ const defineJQueryPlugin = plugin => {
})
}
const execute = callback => {
if (typeof callback === 'function') {
callback()
}
const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue
}
const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
@ -318,10 +289,8 @@ export {
executeAfterTransition,
findShadowRoot,
getElement,
getElementFromSelector,
getjQuery,
getNextActiveElement,
getSelectorFromElement,
getTransitionDurationFromElement,
getUID,
isDisabled,
@ -330,6 +299,7 @@ export {
isVisible,
noop,
onDOMContentLoaded,
parseSelector,
reflow,
triggerTransitionEnd,
toType

View file

@ -1,53 +1,13 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/sanitizer.js
* Bootstrap util/sanitizer.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const uriAttributes = new Set([
'background',
'cite',
'href',
'itemtype',
'longdesc',
'poster',
'src',
'xlink:href'
])
// js-docs-start allow-list
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
/**
* A pattern that recognizes a commonly useful subset of URLs that are safe.
*
* Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
*/
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i
/**
* A pattern that matches safe data URLs. Only matches image, video and audio types.
*
* Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
*/
const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i
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) || DATA_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))
}
export const DefaultAllowlist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
@ -81,6 +41,43 @@ export const DefaultAllowlist = {
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))
}
export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
if (!unsafeHtml.length) {
@ -100,7 +97,6 @@ export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
if (!Object.keys(allowList).includes(elementName)) {
element.remove()
continue
}

View file

@ -1,13 +1,13 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/scrollBar.js
* Bootstrap util/scrollBar.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import SelectorEngine from '../dom/selector-engine'
import Manipulator from '../dom/manipulator'
import { isElement } from './index'
import Manipulator from '../dom/manipulator.js'
import SelectorEngine from '../dom/selector-engine.js'
import { isElement } from './index.js'
/**
* Constants

View file

@ -1,13 +1,13 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/swipe.js
* Bootstrap util/swipe.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import Config from './config'
import EventHandler from '../dom/event-handler'
import { execute } from './index'
import EventHandler from '../dom/event-handler.js'
import Config from './config.js'
import { execute } from './index.js'
/**
* Constants

View file

@ -1,14 +1,14 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): util/template-factory.js
* Bootstrap util/template-factory.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { DefaultAllowlist, sanitizeHtml } from './sanitizer'
import { getElement, isElement } from '../util/index'
import SelectorEngine from '../dom/selector-engine'
import Config from './config'
import SelectorEngine from '../dom/selector-engine.js'
import Config from './config.js'
import { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'
import { execute, getElement, isElement } from './index.js'
/**
* Constants
@ -143,7 +143,7 @@ class TemplateFactory extends Config {
}
_resolvePossibleFunction(arg) {
return typeof arg === 'function' ? arg(this) : arg
return execute(arg, [this])
}
_putElementInTemplate(element, templateElement) {