]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Add missing things in `hide` method of dropdown (#33451)
authorRohit Sharma <rohit2sharma95@gmail.com>
Thu, 1 Apr 2021 18:51:55 +0000 (00:21 +0530)
committerGitHub <noreply@github.com>
Thu, 1 Apr 2021 18:51:55 +0000 (21:51 +0300)
* Update `aria-expanded` attribute in `hide` method

* Remove empty mouseover listeners added for iOS

js/src/dropdown.js
js/tests/unit/dropdown.spec.js

index 605cbc64db9f286f2b3bd8d7c6b8572a5233db6f..6b541ed150b3dfb508a407c2205410758b8cb23d 100644 (file)
@@ -218,12 +218,20 @@ class Dropdown extends BaseComponent {
       return
     }
 
+    // If this is a touch-enabled device we remove the extra
+    // empty mouseover listeners we added for iOS support
+    if ('ontouchstart' in document.documentElement) {
+      [].concat(...document.body.children)
+        .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop()))
+    }
+
     if (this._popper) {
       this._popper.destroy()
     }
 
     this._menu.classList.toggle(CLASS_NAME_SHOW)
     this._element.classList.toggle(CLASS_NAME_SHOW)
+    this._element.setAttribute('aria-expanded', 'false')
     Manipulator.removeDataAttribute(this._menu, 'popper')
     EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
   }
@@ -430,14 +438,13 @@ class Dropdown extends BaseComponent {
           .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop()))
       }
 
-      toggles[i].setAttribute('aria-expanded', 'false')
-
       if (context._popper) {
         context._popper.destroy()
       }
 
       dropdownMenu.classList.remove(CLASS_NAME_SHOW)
       toggles[i].classList.remove(CLASS_NAME_SHOW)
+      toggles[i].setAttribute('aria-expanded', 'false')
       Manipulator.removeDataAttribute(dropdownMenu, 'popper')
       EventHandler.trigger(toggles[i], EVENT_HIDDEN, relatedTarget)
     }
index 03532256a3d2bf16a9dddf678dd32b8a9d5c2a0d..b8969be7c7d790780f922ddb9b37d18f8f4673aa 100644 (file)
@@ -743,7 +743,7 @@ describe('Dropdown', () => {
     it('should hide a dropdown', done => {
       fixtureEl.innerHTML = [
         '<div class="dropdown">',
-        '  <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+        '  <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="true">Dropdown</button>',
         '  <div class="dropdown-menu show">',
         '    <a class="dropdown-item" href="#">Secondary link</a>',
         '  </div>',
@@ -756,6 +756,7 @@ describe('Dropdown', () => {
 
       btnDropdown.addEventListener('hidden.bs.dropdown', () => {
         expect(dropdownMenu.classList.contains('show')).toEqual(false)
+        expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
         done()
       })
 
@@ -894,6 +895,39 @@ describe('Dropdown', () => {
         done()
       })
     })
+
+    it('should remove event listener on touch-enabled device that was added in show method', done => {
+      fixtureEl.innerHTML = [
+        '<div class="dropdown">',
+        '  <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+        '  <div class="dropdown-menu">',
+        '    <a class="dropdown-item" href="#">Dropdwon item</a>',
+        '  </div>',
+        '</div>'
+      ].join('')
+
+      const defaultValueOnTouchStart = document.documentElement.ontouchstart
+      const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+      const dropdown = new Dropdown(btnDropdown)
+
+      document.documentElement.ontouchstart = () => {}
+      spyOn(EventHandler, 'off')
+
+      btnDropdown.addEventListener('shown.bs.dropdown', () => {
+        dropdown.hide()
+      })
+
+      btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+        expect(btnDropdown.classList.contains('show')).toEqual(false)
+        expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
+        expect(EventHandler.off).toHaveBeenCalled()
+
+        document.documentElement.ontouchstart = defaultValueOnTouchStart
+        done()
+      })
+
+      dropdown.show()
+    })
   })
 
   describe('dispose', () => {