From c1ee395f80c05de8317588b07f34a65c5b95c42c Mon Sep 17 00:00:00 2001 From: Jeremy Jackson Date: Thu, 17 Oct 2019 15:01:44 +0000 Subject: [PATCH] Skip hidden dropdowns while focusing (#29523) --- js/src/dropdown.js | 2 ++ js/src/util/index.js | 9 ++++++--- js/tests/unit/dropdown.spec.js | 37 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 06a271ef83..4504d61e09 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -9,6 +9,7 @@ import { getjQuery, getElementFromSelector, isElement, + isVisible, makeArray, noop, typeCheckConfig @@ -478,6 +479,7 @@ class Dropdown { } const items = makeArray(SelectorEngine.find(Selector.VISIBLE_ITEMS, parent)) + .filter(isVisible) if (!items.length) { return diff --git a/js/src/util/index.js b/js/src/util/index.js index 150b4f8773..8a5ae21566 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -138,9 +138,12 @@ const isVisible = element => { } if (element.style && element.parentNode && element.parentNode.style) { - return element.style.display !== 'none' && - element.parentNode.style.display !== 'none' && - element.style.visibility !== 'hidden' + const elementStyle = getComputedStyle(element) + const parentNodeStyle = getComputedStyle(element.parentNode) + + return elementStyle.display !== 'none' && + parentNodeStyle.display !== 'none' && + elementStyle.visibility !== 'hidden' } return false diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index 0046cf6809..7491e38c0d 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -1292,6 +1292,43 @@ describe('Dropdown', () => { triggerDropdown.click() }) + it('should skip hidden element when using keyboard navigation', done => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]') + const dropdown = fixtureEl.querySelector('.dropdown') + + dropdown.addEventListener('shown.bs.dropdown', () => { + const keyDown = createEvent('keydown') + keyDown.which = 40 + + triggerDropdown.dispatchEvent(keyDown) + + expect(document.activeElement.classList.contains('d-none')).toEqual(false, '.d-none not focused') + expect(document.activeElement.style.display === 'none').toEqual(false, '"display: none" not focused') + expect(document.activeElement.style.visibility === 'hidden').toEqual(false, '"visibility: hidden" not focused') + + done() + }) + + triggerDropdown.click() + }) + it('should focus next/previous element when using keyboard navigation', done => { fixtureEl.innerHTML = [ '