This commit is contained in:
Nathan Sarang-Walters 2025-05-01 12:00:22 -07:00 committed by GitHub
commit 2b8f3f31d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 63 additions and 72 deletions

View File

@ -34,7 +34,7 @@
},
{
"path": "./dist/js/bootstrap.bundle.js",
"maxSize": "43.0 kB"
"maxSize": "43.25 kB"
},
{
"path": "./dist/js/bootstrap.bundle.min.js",
@ -42,7 +42,7 @@
},
{
"path": "./dist/js/bootstrap.esm.js",
"maxSize": "28.0 kB"
"maxSize": "28.25 kB"
},
{
"path": "./dist/js/bootstrap.esm.min.js",
@ -54,7 +54,7 @@
},
{
"path": "./dist/js/bootstrap.min.js",
"maxSize": "16.25 kB"
"maxSize": "16.5 kB"
}
],
"ci": {

View File

@ -139,7 +139,7 @@ function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
return [isDelegated, callable, typeEvent]
}
function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
function addHandler(element, originalTypeEvent, handler, delegationFunction, options) {
if (typeof originalTypeEvent !== 'string' || !element) {
return
}
@ -165,7 +165,7 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)
if (previousFunction) {
previousFunction.oneOff = previousFunction.oneOff && oneOff
previousFunction.oneOff = previousFunction.oneOff && options.oneOff
return
}
@ -177,21 +177,22 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
fn.delegationSelector = isDelegated ? handler : null
fn.callable = callable
fn.oneOff = oneOff
fn.oneOff = options.oneOff
fn.uidEvent = uid
handlers[uid] = fn
element.addEventListener(typeEvent, fn, isDelegated)
element.addEventListener(typeEvent, fn, options?.capture ?? false)
}
function removeHandler(element, events, typeEvent, handler, delegationSelector) {
// eslint-disable-next-line max-params
function removeHandler(element, events, typeEvent, handler, delegationSelector, options) {
const fn = findHandler(events[typeEvent], handler, delegationSelector)
if (!fn) {
return
}
element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))
element.removeEventListener(typeEvent, fn, options?.capture ?? false)
delete events[typeEvent][fn.uidEvent]
}
@ -212,15 +213,15 @@ function getTypeEvent(event) {
}
const EventHandler = {
on(element, event, handler, delegationFunction) {
addHandler(element, event, handler, delegationFunction, false)
on(element, event, handler, delegationFunction, options) {
addHandler(element, event, handler, delegationFunction, { ...options, oneOff: false })
},
one(element, event, handler, delegationFunction) {
addHandler(element, event, handler, delegationFunction, true)
one(element, event, handler, delegationFunction, options) {
addHandler(element, event, handler, delegationFunction, { ...options, oneOff: true })
},
off(element, originalTypeEvent, handler, delegationFunction) {
off(element, originalTypeEvent, handler, delegationFunction, options) {
if (typeof originalTypeEvent !== 'string' || !element) {
return
}
@ -237,7 +238,7 @@ const EventHandler = {
return
}
removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)
removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null, options)
return
}
@ -251,7 +252,7 @@ const EventHandler = {
const handlerKey = keyHandlers.replace(stripUidRegex, '')
if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector, options)
}
}
},

View File

@ -440,14 +440,14 @@ class Dropdown extends BaseComponent {
* Data API implementation
*/
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler, { capture: true })
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler, { capture: true })
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus, { capture: true })
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus, { capture: true })
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault()
Dropdown.getOrCreateInstance(this).toggle()
})
}, { capture: true })
/**
* jQuery

View File

@ -514,28 +514,20 @@ describe('Collapse', () => {
describe('data-api', () => {
it('should prevent url change if click on nested elements', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<a role="button" data-bs-toggle="collapse" class="collapsed" href="#collapse">',
' <span id="nested"></span>',
'</a>',
'<div id="collapse" class="collapse"></div>'
].join('')
fixtureEl.innerHTML = [
'<a role="button" data-bs-toggle="collapse" class="collapsed" href="#collapse">',
' <span id="nested"></span>',
'</a>',
'<div id="collapse" class="collapse"></div>'
].join('')
const triggerEl = fixtureEl.querySelector('a')
const nestedTriggerEl = fixtureEl.querySelector('#nested')
const nestedTriggerEl = fixtureEl.querySelector('#nested')
const spy = spyOn(Event.prototype, 'preventDefault').and.callThrough()
const spy = spyOn(Event.prototype, 'preventDefault').and.callThrough()
triggerEl.addEventListener('click', event => {
expect(event.target.isEqualNode(nestedTriggerEl)).toBeTrue()
expect(event.delegateTarget.isEqualNode(triggerEl)).toBeTrue()
expect(spy).toHaveBeenCalled()
resolve()
})
nestedTriggerEl.click()
nestedTriggerEl.click()
})
expect(spy).toHaveBeenCalled()
})
it('should show multiple collapsed elements', () => {

View File

@ -1361,7 +1361,7 @@ describe('Dropdown', () => {
btnDropdown.addEventListener('shown.bs.dropdown', () => {
expect(btnDropdown).toHaveClass('show')
const keyup = createEvent('keyup')
const keyup = createEvent('keyup', { bubbles: true })
keyup.key = 'Tab'
document.dispatchEvent(keyup)
@ -1456,7 +1456,7 @@ describe('Dropdown', () => {
expect(triggerDropdownFirst).toHaveClass('show')
expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
const keyup = createEvent('keyup')
const keyup = createEvent('keyup', { bubbles: true })
keyup.key = 'Tab'
document.dispatchEvent(keyup)
@ -1471,7 +1471,7 @@ describe('Dropdown', () => {
expect(triggerDropdownLast).toHaveClass('show')
expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
const keyup = createEvent('keyup')
const keyup = createEvent('keyup', { bubbles: true })
keyup.key = 'Tab'
document.dispatchEvent(keyup)
@ -1570,7 +1570,7 @@ describe('Dropdown', () => {
})
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'Escape'
triggerDropdown.dispatchEvent(keydown)
@ -1637,7 +1637,7 @@ describe('Dropdown', () => {
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
input.focus()
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'ArrowUp'
input.dispatchEvent(keydown)
@ -1671,7 +1671,7 @@ describe('Dropdown', () => {
const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'ArrowDown'
triggerDropdown.dispatchEvent(keydown)
@ -1708,7 +1708,7 @@ describe('Dropdown', () => {
const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'ArrowDown'
triggerDropdown.dispatchEvent(keydown)
@ -1741,7 +1741,7 @@ describe('Dropdown', () => {
const item2 = fixtureEl.querySelector('#item2')
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
const keydownArrowDown = createEvent('keydown')
const keydownArrowDown = createEvent('keydown', { bubbles: true })
keydownArrowDown.key = 'ArrowDown'
triggerDropdown.dispatchEvent(keydownArrowDown)
@ -1750,7 +1750,7 @@ describe('Dropdown', () => {
document.activeElement.dispatchEvent(keydownArrowDown)
expect(document.activeElement).toEqual(item2, 'item2 is focused')
const keydownArrowUp = createEvent('keydown')
const keydownArrowUp = createEvent('keydown', { bubbles: true })
keydownArrowUp.key = 'ArrowUp'
document.activeElement.dispatchEvent(keydownArrowUp)
@ -1785,7 +1785,7 @@ describe('Dropdown', () => {
})
})
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'ArrowUp'
triggerDropdown.dispatchEvent(keydown)
})
@ -1813,7 +1813,7 @@ describe('Dropdown', () => {
})
})
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'ArrowDown'
triggerDropdown.dispatchEvent(keydown)
})
@ -1840,7 +1840,7 @@ describe('Dropdown', () => {
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
expect(triggerDropdown).toHaveClass('show')
input.dispatchEvent(createEvent('click'))
input.dispatchEvent(createEvent('click', { bubbles: true }))
})
triggerDropdown.click()
@ -1868,7 +1868,7 @@ describe('Dropdown', () => {
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
expect(triggerDropdown).toHaveClass('show')
textarea.dispatchEvent(createEvent('click'))
textarea.dispatchEvent(createEvent('click', { bubbles: true }))
})
triggerDropdown.click()
@ -1895,9 +1895,7 @@ describe('Dropdown', () => {
})
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
input.dispatchEvent(createEvent('click', {
bubbles: true
}))
input.dispatchEvent(createEvent('click', { bubbles: true }))
})
triggerDropdown.click()
@ -1922,14 +1920,14 @@ describe('Dropdown', () => {
const textarea = fixtureEl.querySelector('textarea')
const test = (eventKey, elementToDispatch) => {
const event = createEvent('keydown')
const event = createEvent('keydown', { bubbles: true })
event.key = eventKey
elementToDispatch.focus()
elementToDispatch.dispatchEvent(event)
expect(document.activeElement).toEqual(elementToDispatch, `${elementToDispatch.tagName} still focused`)
}
const keydownEscape = createEvent('keydown')
const keydownEscape = createEvent('keydown', { bubbles: true })
keydownEscape.key = 'Escape'
triggerDropdown.addEventListener('shown.bs.dropdown', () => {
@ -1985,7 +1983,7 @@ describe('Dropdown', () => {
// Key escape
button.focus()
// Key escape
const keydownEscape = createEvent('keydown')
const keydownEscape = createEvent('keydown', { bubbles: true })
keydownEscape.key = 'Escape'
button.dispatchEvent(keydownEscape)
@ -2351,10 +2349,10 @@ describe('Dropdown', () => {
const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
const dropdown = fixtureEl.querySelector('.dropdown')
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'ArrowDown'
const keyup = createEvent('keyup')
const keyup = createEvent('keyup', { bubbles: true })
keyup.key = 'ArrowUp'
const handleArrowDown = () => {

View File

@ -246,7 +246,7 @@ describe('Toast', () => {
resolve()
})
const mouseOverEvent = createEvent('mouseover')
const mouseOverEvent = createEvent('mouseover', { bubbles: true })
toastEl.dispatchEvent(mouseOverEvent)
}, toast._config.delay / 2)
@ -309,7 +309,7 @@ describe('Toast', () => {
})
toastEl.addEventListener('focusin', () => {
const mouseOutEvent = createEvent('mouseout')
const mouseOutEvent = createEvent('mouseout', { bubbles: true })
toastEl.dispatchEvent(mouseOutEvent)
})
@ -323,7 +323,7 @@ describe('Toast', () => {
resolve()
})
const mouseOverEvent = createEvent('mouseover')
const mouseOverEvent = createEvent('mouseover', { bubbles: true })
toastEl.dispatchEvent(mouseOverEvent)
}, toast._config.delay / 2)
@ -362,7 +362,7 @@ describe('Toast', () => {
resolve()
})
const mouseOverEvent = createEvent('mouseover')
const mouseOverEvent = createEvent('mouseover', { bubbles: true })
toastEl.dispatchEvent(mouseOverEvent)
}, toast._config.delay / 2)
@ -392,7 +392,7 @@ describe('Toast', () => {
})
toastEl.addEventListener('focusin', () => {
const mouseOutEvent = createEvent('mouseout')
const mouseOutEvent = createEvent('mouseout', { bubbles: true })
toastEl.dispatchEvent(mouseOutEvent)
})
@ -401,7 +401,7 @@ describe('Toast', () => {
resolve()
})
const mouseOverEvent = createEvent('mouseover')
const mouseOverEvent = createEvent('mouseover', { bubbles: true })
toastEl.dispatchEvent(mouseOverEvent)
}, toast._config.delay / 2)

View File

@ -39,7 +39,7 @@ describe('Plugin functions', () => {
const spyTest = spyOn(DummyClass2.prototype, 'testMethod')
const componentWrapper = fixtureEl.querySelector('#foo')
const btnClose = fixtureEl.querySelector('[data-bs-dismiss="test"]')
const event = createEvent('click')
const event = createEvent('click', { bubbles: true })
enableDismissTrigger(DummyClass2, 'testMethod')
btnClose.dispatchEvent(event)
@ -59,7 +59,7 @@ describe('Plugin functions', () => {
const spyHide = spyOn(DummyClass2.prototype, 'hide')
const componentWrapper = fixtureEl.querySelector('#foo')
const btnClose = fixtureEl.querySelector('[data-bs-dismiss="test"]')
const event = createEvent('click')
const event = createEvent('click', { bubbles: true })
enableDismissTrigger(DummyClass2)
btnClose.dispatchEvent(event)
@ -77,7 +77,7 @@ describe('Plugin functions', () => {
const spy = spyOn(DummyClass2, 'getOrCreateInstance').and.callThrough()
const btnClose = fixtureEl.querySelector('[data-bs-dismiss="test"]')
const event = createEvent('click')
const event = createEvent('click', { bubbles: true })
enableDismissTrigger(DummyClass2)
btnClose.dispatchEvent(event)
@ -93,7 +93,7 @@ describe('Plugin functions', () => {
].join('')
const btnClose = fixtureEl.querySelector('[data-bs-dismiss="test"]')
const event = createEvent('click')
const event = createEvent('click', { bubbles: true })
enableDismissTrigger(DummyClass2)
const spy = spyOn(Event.prototype, 'preventDefault').and.callThrough()

View File

@ -107,7 +107,7 @@ describe('FocusTrap', () => {
first.addEventListener('focusin', focusInListener)
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'Tab'
document.dispatchEvent(keydown)
@ -146,7 +146,7 @@ describe('FocusTrap', () => {
last.addEventListener('focusin', focusInListener)
const keydown = createEvent('keydown')
const keydown = createEvent('keydown', { bubbles: true })
keydown.key = 'Tab'
keydown.shiftKey = true