diff options
author | alpadev <2838324+alpadev@users.noreply.github.com> | 2021-04-01 21:44:04 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-01 21:44:04 +0300 |
commit | f36f8344533d3179b8d82af96e005b3106d9ab46 (patch) | |
tree | 30c7aa61741b4315dee44d40a8c4df1af7911043 /js | |
parent | 6e7f1a9a347f4cc38a8973044440afa52f2cffcd (diff) |
Fix dropdown escape propagation (#33479)
Diffstat (limited to 'js')
-rw-r--r-- | js/src/dropdown.js | 63 | ||||
-rw-r--r-- | js/tests/unit/dropdown.spec.js | 33 |
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', () => { |