]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Fix event handler removal in dropdown/carousel dispose (#33000)
authorKyle Tsang <6854874+kyletsang@users.noreply.github.com>
Fri, 12 Feb 2021 05:51:34 +0000 (21:51 -0800)
committerGitHub <noreply@github.com>
Fri, 12 Feb 2021 05:51:34 +0000 (07:51 +0200)
* Fix event handler removal in carousel dispose

* Fix event handler removal in dropdown dispose

* Test event handlers in scrollspy dispose

* Test event handlers in toast dispose

* Test event handlers in tooltip dispose

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
Co-authored-by: Rohit Sharma <rohit2sharma95@gmail.com>
.bundlewatch.config.json
js/src/carousel.js
js/src/dropdown.js
js/tests/unit/carousel.spec.js
js/tests/unit/dropdown.spec.js
js/tests/unit/scrollspy.spec.js
js/tests/unit/toast.spec.js
js/tests/unit/tooltip.spec.js

index 36404b38cfda0dc0206614dd7f31521e3c3e9355..bd9ce671d45e57bd9ccbdfbb57e1e42d78a77014 100644 (file)
@@ -38,7 +38,7 @@
     },
     {
       "path": "./dist/js/bootstrap.bundle.min.js",
-      "maxSize": "21.5 kB"
+      "maxSize": "21.75 kB"
     },
     {
       "path": "./dist/js/bootstrap.esm.js",
@@ -54,7 +54,7 @@
     },
     {
       "path": "./dist/js/bootstrap.min.js",
-      "maxSize": "15.5 kB"
+      "maxSize": "15.75 kB"
     }
   ],
   "ci": {
index e4c13d5931057cde3c32b573afa4047fbc317b25..17814d42de280bcaa320a86757432dbc03da6099 100644 (file)
@@ -216,7 +216,6 @@ class Carousel extends BaseComponent {
   }
 
   dispose() {
-    super.dispose()
     EventHandler.off(this._element, EVENT_KEY)
 
     this._items = null
@@ -226,6 +225,8 @@ class Carousel extends BaseComponent {
     this._isSliding = null
     this._activeElement = null
     this._indicatorsElement = null
+
+    super.dispose()
   }
 
   // Private
index 2516b945a3b191948aa9868467efc5138eb4f7ee..97c0f50520f9ebe7f98543ac83b0da2e3e440a27 100644 (file)
@@ -232,7 +232,6 @@ class Dropdown extends BaseComponent {
   }
 
   dispose() {
-    super.dispose()
     EventHandler.off(this._element, EVENT_KEY)
     this._menu = null
 
@@ -240,6 +239,8 @@ class Dropdown extends BaseComponent {
       this._popper.destroy()
       this._popper = null
     }
+
+    super.dispose()
   }
 
   update() {
index 0571ac9af890d4b8dfaa59f12e2e879c89d7458a..5c45efe0c10fd5595f7be76b36007e3330eae917 100644 (file)
@@ -295,6 +295,8 @@ describe('Carousel', () => {
 
       spyOn(Carousel.prototype, '_addTouchEventListeners')
 
+      // Headless browser does not support touch events, so need to fake it
+      // to test that touch events are add properly.
       document.documentElement.ontouchstart = () => {}
       const carousel = new Carousel(carouselEl)
 
@@ -1056,13 +1058,30 @@ describe('Carousel', () => {
       ].join('')
 
       const carouselEl = fixtureEl.querySelector('#myCarousel')
+      const addEventSpy = spyOn(carouselEl, 'addEventListener').and.callThrough()
+      const removeEventSpy = spyOn(carouselEl, 'removeEventListener').and.callThrough()
+
+      // Headless browser does not support touch events, so need to fake it
+      // to test that touch events are add/removed properly.
+      document.documentElement.ontouchstart = () => {}
+
       const carousel = new Carousel(carouselEl)
 
-      spyOn(EventHandler, 'off').and.callThrough()
+      const expectedArgs = [
+        ['keydown', jasmine.any(Function), jasmine.any(Boolean)],
+        ['mouseover', jasmine.any(Function), jasmine.any(Boolean)],
+        ['mouseout', jasmine.any(Function), jasmine.any(Boolean)],
+        ['pointerdown', jasmine.any(Function), jasmine.any(Boolean)],
+        ['pointerup', jasmine.any(Function), jasmine.any(Boolean)]
+      ]
+
+      expect(addEventSpy.calls.allArgs()).toEqual(expectedArgs)
 
       carousel.dispose()
 
-      expect(EventHandler.off).toHaveBeenCalled()
+      expect(removeEventSpy.calls.allArgs()).toEqual(expectedArgs)
+
+      delete document.documentElement.ontouchstart
     })
   })
 
index e97ce7717ce6dc8d684a6ca633bd7e04a441c923..04c35059e7bee5d49c549ae81b3e4ec730d09ed0 100644 (file)
@@ -884,16 +884,21 @@ describe('Dropdown', () => {
       ].join('')
 
       const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+      spyOn(btnDropdown, 'addEventListener').and.callThrough()
+      spyOn(btnDropdown, 'removeEventListener').and.callThrough()
+
       const dropdown = new Dropdown(btnDropdown)
 
       expect(dropdown._popper).toBeNull()
       expect(dropdown._menu).toBeDefined()
       expect(dropdown._element).toBeDefined()
+      expect(btnDropdown.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), jasmine.any(Boolean))
 
       dropdown.dispose()
 
       expect(dropdown._menu).toBeNull()
       expect(dropdown._element).toBeNull()
+      expect(btnDropdown.removeEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), jasmine.any(Boolean))
     })
 
     it('should dispose dropdown with Popper', () => {
index 0d175aafa384fde55c6d57b0aa01b29cb742ceda..917593f3987cd1685c5ee4d24205882b47bc0a32 100644 (file)
@@ -1,6 +1,5 @@
 import ScrollSpy from '../../src/scrollspy'
 import Manipulator from '../../src/dom/manipulator'
-import EventHandler from '../../src/dom/event-handler'
 
 /** Test helpers */
 import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture'
@@ -560,14 +559,18 @@ describe('ScrollSpy', () => {
 
   describe('dispose', () => {
     it('should dispose a scrollspy', () => {
-      spyOn(EventHandler, 'off')
       fixtureEl.innerHTML = '<div style="display: none;"></div>'
 
       const divEl = fixtureEl.querySelector('div')
+      spyOn(divEl, 'addEventListener').and.callThrough()
+      spyOn(divEl, 'removeEventListener').and.callThrough()
+
       const scrollSpy = new ScrollSpy(divEl)
+      expect(divEl.addEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function), jasmine.any(Boolean))
 
       scrollSpy.dispose()
-      expect(EventHandler.off).toHaveBeenCalledWith(divEl, '.bs.scrollspy')
+
+      expect(divEl.removeEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function), jasmine.any(Boolean))
     })
   })
 
index 2920eb2efa0f3e8543d18fbe1f33b71dc27fcd89..44f74aa36dab4965b0b952f2916d26c8f12feb49 100644 (file)
@@ -274,13 +274,18 @@ describe('Toast', () => {
       fixtureEl.innerHTML = '<div></div>'
 
       const toastEl = fixtureEl.querySelector('div')
+      spyOn(toastEl, 'addEventListener').and.callThrough()
+      spyOn(toastEl, 'removeEventListener').and.callThrough()
+
       const toast = new Toast(toastEl)
 
       expect(Toast.getInstance(toastEl)).toBeDefined()
+      expect(toastEl.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), jasmine.any(Boolean))
 
       toast.dispose()
 
       expect(Toast.getInstance(toastEl)).toBeNull()
+      expect(toastEl.removeEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), jasmine.any(Boolean))
     })
 
     it('should allow to destroy toast and hide it before that', done => {
index e1d037154661b9766496462bed118cbab3ca60b6..84f5abcdade1018933f52d02afb968d5dff9eec7 100644 (file)
@@ -327,13 +327,26 @@ describe('Tooltip', () => {
       fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
 
       const tooltipEl = fixtureEl.querySelector('a')
+      const addEventSpy = spyOn(tooltipEl, 'addEventListener').and.callThrough()
+      const removeEventSpy = spyOn(tooltipEl, 'removeEventListener').and.callThrough()
+
       const tooltip = new Tooltip(tooltipEl)
 
       expect(Tooltip.getInstance(tooltipEl)).toEqual(tooltip)
 
+      const expectedArgs = [
+        ['mouseover', jasmine.any(Function), jasmine.any(Boolean)],
+        ['mouseout', jasmine.any(Function), jasmine.any(Boolean)],
+        ['focusin', jasmine.any(Function), jasmine.any(Boolean)],
+        ['focusout', jasmine.any(Function), jasmine.any(Boolean)]
+      ]
+
+      expect(addEventSpy.calls.allArgs()).toEqual(expectedArgs)
+
       tooltip.dispose()
 
       expect(Tooltip.getInstance(tooltipEl)).toEqual(null)
+      expect(removeEventSpy.calls.allArgs()).toEqual(expectedArgs)
     })
 
     it('should destroy a tooltip after it is shown and hidden', done => {