mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-12 08:34:08 +02:00
Keep role="dialog"
after closing modal/offcanvas if already in the markup
This commit is contained in:
@@ -67,6 +67,7 @@ class Modal extends BaseComponent {
|
|||||||
constructor(element, config) {
|
constructor(element, config) {
|
||||||
super(element, config)
|
super(element, config)
|
||||||
|
|
||||||
|
this._deleteDialogRoleWhenHiding = false
|
||||||
this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)
|
this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)
|
||||||
this._backdrop = this._initializeBackDrop()
|
this._backdrop = this._initializeBackDrop()
|
||||||
this._focustrap = this._initializeFocusTrap()
|
this._focustrap = this._initializeFocusTrap()
|
||||||
@@ -177,7 +178,12 @@ class Modal extends BaseComponent {
|
|||||||
this._element.style.display = 'block'
|
this._element.style.display = 'block'
|
||||||
this._element.removeAttribute('aria-hidden')
|
this._element.removeAttribute('aria-hidden')
|
||||||
this._element.setAttribute('aria-modal', true)
|
this._element.setAttribute('aria-modal', true)
|
||||||
this._element.setAttribute('role', 'dialog')
|
|
||||||
|
if (this._element.getAttribute('role') !== 'dialog') {
|
||||||
|
this._deleteDialogRoleWhenHiding = true
|
||||||
|
this._element.setAttribute('role', 'dialog')
|
||||||
|
}
|
||||||
|
|
||||||
this._element.scrollTop = 0
|
this._element.scrollTop = 0
|
||||||
|
|
||||||
const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)
|
const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)
|
||||||
@@ -246,7 +252,11 @@ class Modal extends BaseComponent {
|
|||||||
this._element.style.display = 'none'
|
this._element.style.display = 'none'
|
||||||
this._element.setAttribute('aria-hidden', true)
|
this._element.setAttribute('aria-hidden', true)
|
||||||
this._element.removeAttribute('aria-modal')
|
this._element.removeAttribute('aria-modal')
|
||||||
this._element.removeAttribute('role')
|
|
||||||
|
if (this._deleteDialogRoleWhenHiding) {
|
||||||
|
this._element.removeAttribute('role')
|
||||||
|
}
|
||||||
|
|
||||||
this._isTransitioning = false
|
this._isTransitioning = false
|
||||||
|
|
||||||
this._backdrop.hide(() => {
|
this._backdrop.hide(() => {
|
||||||
|
@@ -66,6 +66,7 @@ class Offcanvas extends BaseComponent {
|
|||||||
constructor(element, config) {
|
constructor(element, config) {
|
||||||
super(element, config)
|
super(element, config)
|
||||||
|
|
||||||
|
this._deleteDialogRoleWhenHiding = false
|
||||||
this._isShown = false
|
this._isShown = false
|
||||||
this._backdrop = this._initializeBackDrop()
|
this._backdrop = this._initializeBackDrop()
|
||||||
this._focustrap = this._initializeFocusTrap()
|
this._focustrap = this._initializeFocusTrap()
|
||||||
@@ -109,7 +110,12 @@ class Offcanvas extends BaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._element.setAttribute('aria-modal', true)
|
this._element.setAttribute('aria-modal', true)
|
||||||
this._element.setAttribute('role', 'dialog')
|
|
||||||
|
if (this._element.getAttribute('role') !== 'dialog') {
|
||||||
|
this._deleteDialogRoleWhenHiding = true
|
||||||
|
this._element.setAttribute('role', 'dialog')
|
||||||
|
}
|
||||||
|
|
||||||
this._element.classList.add(CLASS_NAME_SHOWING)
|
this._element.classList.add(CLASS_NAME_SHOWING)
|
||||||
|
|
||||||
const completeCallBack = () => {
|
const completeCallBack = () => {
|
||||||
@@ -145,7 +151,10 @@ class Offcanvas extends BaseComponent {
|
|||||||
const completeCallback = () => {
|
const completeCallback = () => {
|
||||||
this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)
|
this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)
|
||||||
this._element.removeAttribute('aria-modal')
|
this._element.removeAttribute('aria-modal')
|
||||||
this._element.removeAttribute('role')
|
|
||||||
|
if (this._deleteDialogRoleWhenHiding) {
|
||||||
|
this._element.removeAttribute('role')
|
||||||
|
}
|
||||||
|
|
||||||
if (!this._config.scroll) {
|
if (!this._config.scroll) {
|
||||||
new ScrollBarHelper().reset()
|
new ScrollBarHelper().reset()
|
||||||
|
@@ -709,6 +709,35 @@ describe('Modal', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should hide a modal and not remove role="dialog" if already present', () => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
fixtureEl.innerHTML = '<div class="modal" role="dialog"><div class="modal-dialog"></div></div>'
|
||||||
|
|
||||||
|
const modalEl = fixtureEl.querySelector('.modal')
|
||||||
|
const modal = new Modal(modalEl)
|
||||||
|
const backdropSpy = spyOn(modal._backdrop, 'hide').and.callThrough()
|
||||||
|
|
||||||
|
modalEl.addEventListener('shown.bs.modal', () => {
|
||||||
|
modal.hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
modalEl.addEventListener('hide.bs.modal', event => {
|
||||||
|
expect(event).toBeDefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
modalEl.addEventListener('hidden.bs.modal', () => {
|
||||||
|
expect(modalEl.getAttribute('aria-modal')).toBeNull()
|
||||||
|
expect(modalEl.getAttribute('role')).toEqual('dialog')
|
||||||
|
expect(modalEl.getAttribute('aria-hidden')).toEqual('true')
|
||||||
|
expect(modalEl.style.display).toEqual('none')
|
||||||
|
expect(backdropSpy).toHaveBeenCalled()
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
modal.show()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should close modal when clicking outside of modal-content', () => {
|
it('should close modal when clicking outside of modal-content', () => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||||
|
@@ -551,6 +551,26 @@ describe('Offcanvas', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should hide a shown element and not remove role="dialog" if already present', () => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
fixtureEl.innerHTML = '<div class="offcanvas" role="dialog"></div>'
|
||||||
|
|
||||||
|
const offCanvasEl = fixtureEl.querySelector('div')
|
||||||
|
const offCanvas = new Offcanvas(offCanvasEl)
|
||||||
|
const spy = spyOn(offCanvas._backdrop, 'hide').and.callThrough()
|
||||||
|
offCanvas.show()
|
||||||
|
|
||||||
|
offCanvasEl.addEventListener('hidden.bs.offcanvas', () => {
|
||||||
|
expect(offCanvasEl).not.toHaveClass('show')
|
||||||
|
expect(offCanvasEl.getAttribute('role')).toEqual('dialog')
|
||||||
|
expect(spy).toHaveBeenCalled()
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
offCanvas.hide()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should not fire hidden when hide is prevented', () => {
|
it('should not fire hidden when hide is prevented', () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
|
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
|
||||||
|
Reference in New Issue
Block a user