Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authoralpadev <2838324+alpadev@users.noreply.github.com>2021-04-01 21:44:04 +0300
committerGitHub <noreply@github.com>2021-04-01 21:44:04 +0300
commitf36f8344533d3179b8d82af96e005b3106d9ab46 (patch)
tree30c7aa61741b4315dee44d40a8c4df1af7911043 /js
parent6e7f1a9a347f4cc38a8973044440afa52f2cffcd (diff)
Fix dropdown escape propagation (#33479)
Diffstat (limited to 'js')
-rw-r--r--js/src/dropdown.js63
-rw-r--r--js/tests/unit/dropdown.spec.js33
2 files changed, 68 insertions, 28 deletions
diff --git a/js/src/dropdown.js b/js/src/dropdown.js
index 97bf6e1099..605cbc64db 100644
--- a/js/src/dropdown.js
+++ b/js/src/dropdown.js
@@ -443,6 +443,31 @@ class Dropdown extends BaseComponent {
}
}
+ static selectMenuItem(parent, event) {
+ const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent).filter(isVisible)
+
+ if (!items.length) {
+ return
+ }
+
+ let index = items.indexOf(event.target)
+
+ // Up
+ if (event.key === ARROW_UP_KEY && index > 0) {
+ index--
+ }
+
+ // Down
+ if (event.key === ARROW_DOWN_KEY && index < items.length - 1) {
+ index++
+ }
+
+ // index is -1 if the first keydown is an ArrowUp
+ index = index === -1 ? 0 : index
+
+ items[index].focus()
+ }
+
static getParentFromElement(element) {
return getElementFromSelector(element) || element.parentNode
}
@@ -463,6 +488,12 @@ class Dropdown extends BaseComponent {
return
}
+ const isActive = this.classList.contains(CLASS_NAME_SHOW)
+
+ if (!isActive && event.key === ESCAPE_KEY) {
+ return
+ }
+
event.preventDefault()
event.stopPropagation()
@@ -470,19 +501,16 @@ class Dropdown extends BaseComponent {
return
}
- const parent = Dropdown.getParentFromElement(this)
- const isActive = this.classList.contains(CLASS_NAME_SHOW)
+ const getToggleButton = () => this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]
if (event.key === ESCAPE_KEY) {
- const button = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]
- button.focus()
+ getToggleButton().focus()
Dropdown.clearMenus()
return
}
if (!isActive && (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY)) {
- const button = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]
- button.click()
+ getToggleButton().click()
return
}
@@ -491,28 +519,7 @@ class Dropdown extends BaseComponent {
return
}
- const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent).filter(isVisible)
-
- if (!items.length) {
- return
- }
-
- let index = items.indexOf(event.target)
-
- // Up
- if (event.key === ARROW_UP_KEY && index > 0) {
- index--
- }
-
- // Down
- if (event.key === ARROW_DOWN_KEY && index < items.length - 1) {
- index++
- }
-
- // index is -1 if the first keydown is an ArrowUp
- index = index === -1 ? 0 : index
-
- items[index].focus()
+ Dropdown.selectMenuItem(Dropdown.getParentFromElement(this), event)
}
}
diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js
index ad51d487bf..03532256a3 100644
--- a/js/tests/unit/dropdown.spec.js
+++ b/js/tests/unit/dropdown.spec.js
@@ -1671,6 +1671,39 @@ describe('Dropdown', () => {
done()
}, 20)
})
+
+ it('should propagate escape key events if dropdown is closed', done => {
+ fixtureEl.innerHTML = [
+ '<div class="parent">',
+ ' <div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Some Item</a>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ]
+
+ const parent = fixtureEl.querySelector('.parent')
+ const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+
+ const parentKeyHandler = jasmine.createSpy('parentKeyHandler')
+
+ parent.addEventListener('keydown', parentKeyHandler)
+ parent.addEventListener('keyup', () => {
+ expect(parentKeyHandler).toHaveBeenCalled()
+ done()
+ })
+
+ const keydownEscape = createEvent('keydown', { bubbles: true })
+ keydownEscape.key = 'Escape'
+ const keyupEscape = createEvent('keyup', { bubbles: true })
+ keyupEscape.key = 'Escape'
+
+ toggle.focus()
+ toggle.dispatchEvent(keydownEscape)
+ toggle.dispatchEvent(keyupEscape)
+ })
})
describe('jQueryInterface', () => {