This commit is contained in:
Roni Diwan 2025-05-02 08:45:32 +00:00 committed by GitHub
commit 66f9445ed2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 114 additions and 3 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",

View File

@ -174,6 +174,12 @@ class Offcanvas extends BaseComponent {
this.hide()
}
const keydownCallback = event => {
if (event.key === ESCAPE_KEY) {
this.hide()
}
}
// 'static' option will be translated to true, and booleans will keep their value
const isVisible = Boolean(this._config.backdrop)
@ -182,7 +188,8 @@ class Offcanvas extends BaseComponent {
isVisible,
isAnimated: true,
rootElement: this._element.parentNode,
clickCallback: isVisible ? clickCallback : null
clickCallback: isVisible ? clickCallback : null,
keydownCallback: this._config.keyboard ? keydownCallback : null
})
}

View File

@ -18,6 +18,8 @@ import {
const NAME = 'backdrop'
const CLASS_NAME_FADE = 'fade'
const CLASS_NAME_SHOW = 'show'
const EVENT_KEY = `.bs.${NAME}`
const EVENT_KEYDOWN = `keydown.bs.${NAME}`
const EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`
const Default = {
@ -25,6 +27,7 @@ const Default = {
clickCallback: null,
isAnimated: false,
isVisible: true, // if false, we use the backdrop helper without adding any element to the dom
keydownCallback: null,
rootElement: 'body' // give the choice to place backdrop under different elements
}
@ -33,6 +36,7 @@ const DefaultType = {
clickCallback: '(function|null)',
isAnimated: 'boolean',
isVisible: 'boolean',
keydownCallback: '(function|null)',
rootElement: '(element|string)'
}
@ -101,7 +105,7 @@ class Backdrop extends Config {
return
}
EventHandler.off(this._element, EVENT_MOUSEDOWN)
EventHandler.off(this._element, EVENT_KEY)
this._element.remove()
this._isAppended = false
@ -140,6 +144,12 @@ class Backdrop extends Config {
execute(this._config.clickCallback)
})
if (this._config.keydownCallback) {
EventHandler.on(document, EVENT_KEYDOWN, event => {
execute(this._config.keydownCallback, [event])
})
}
this._isAppended = true
}

View File

@ -158,6 +158,74 @@ describe('Offcanvas', () => {
})
})
it('should hide if backdrop is static and esc key is pressed on document', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl, { backdrop: 'static' })
const keydownEscEvent = createEvent('keydown')
keydownEscEvent.key = 'Escape'
const spyHide = spyOn(offCanvas, 'hide')
offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
document.dispatchEvent(keydownEscEvent)
expect(spyHide).toHaveBeenCalled()
resolve()
})
offCanvas.show()
})
})
it('should not hide if backdrop is static and esc key is pressed on document but keyboard = false', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl, { backdrop: 'static', keyboard: false })
const keydownEscEvent = createEvent('keydown')
keydownEscEvent.key = 'Escape'
const spyHide = spyOn(offCanvas, 'hide')
offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
expect(offCanvas._config.keyboard).toBeFalse()
document.dispatchEvent(keydownEscEvent)
expect(spyHide).not.toHaveBeenCalled()
resolve()
})
offCanvas.show()
})
})
it('should not hide if backdrop is static but key other than esc is pressed on document', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl, { backdrop: 'static' })
const keydownEvent = createEvent('keydown')
keydownEvent.key = 'Tab'
const spyHide = spyOn(offCanvas, 'hide')
offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
document.dispatchEvent(keydownEvent)
expect(spyHide).not.toHaveBeenCalled()
resolve()
})
offCanvas.show()
})
})
it('should call `hide` on resize, if element\'s position is not fixed any more', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<div class="offcanvas-lg"></div>'

View File

@ -191,6 +191,32 @@ describe('Backdrop', () => {
})
})
describe('keydown callback', () => {
it('should execute keydown callback on keydown event', () => {
return new Promise(resolve => {
const spy = jasmine.createSpy('spy')
const instance = new Backdrop({
isVisible: true,
isAnimated: false,
keydownCallback: () => spy()
})
const endTest = () => {
setTimeout(() => {
expect(spy).toHaveBeenCalled()
resolve()
}, 10)
}
instance.show(() => {
const keydownEvent = new Event('keydown', { bubbles: true, cancelable: true })
document.querySelector(CLASS_BACKDROP).dispatchEvent(keydownEvent)
endTest()
})
})
})
})
describe('animation callbacks', () => {
it('should show and hide backdrop after counting transition duration if it is animated', () => {
return new Promise(resolve => {