]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Tab.js: Fixes on click handling (#33586)
authorGeoSot <geo.sotis@gmail.com>
Tue, 20 Apr 2021 05:26:58 +0000 (08:26 +0300)
committerGitHub <noreply@github.com>
Tue, 20 Apr 2021 05:26:58 +0000 (08:26 +0300)
* use prevent default only if triggered by anchor
* disable auto-initialization if trigger is disabled

js/src/tab.js
js/tests/unit/tab.spec.js

index ffca5f299ee6bfe553afa4d46147c53a56d66638..4d823cc61c74a4bc16469842bc8a65c7cc5df1eb 100644 (file)
@@ -66,8 +66,7 @@ class Tab extends BaseComponent {
   show() {
     if ((this._element.parentNode &&
       this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
-      this._element.classList.contains(CLASS_NAME_ACTIVE)) ||
-      isDisabled(this._element)) {
+      this._element.classList.contains(CLASS_NAME_ACTIVE))) {
       return
     }
 
@@ -202,7 +201,13 @@ class Tab extends BaseComponent {
  */
 
 EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
-  event.preventDefault()
+  if (['A', 'AREA'].includes(this.tagName)) {
+    event.preventDefault()
+  }
+
+  if (isDisabled(this)) {
+    return
+  }
 
   const data = Data.get(this, DATA_KEY) || new Tab(this)
   data.show()
index 5b98bad9d5089b70c87987c165e551ef04b25902..4741b495de839f712d3e85d0debabd1b2c1d8a76 100644 (file)
@@ -198,58 +198,6 @@ describe('Tab', () => {
       }, 30)
     })
 
-    it('should not fire shown when tab has disabled attribute', done => {
-      fixtureEl.innerHTML = [
-        '<ul class="nav nav-tabs" role="tablist">',
-        '  <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
-        '  <li class="nav-item" role="presentation"><button type="button" data-bs-target="#profile" class="nav-link" disabled role="tab">Profile</button></li>',
-        '</ul>',
-        '<div class="tab-content">',
-        '  <div class="tab-pane active" id="home" role="tabpanel"></div>',
-        '  <div class="tab-pane" id="profile" role="tabpanel"></div>',
-        '</div>'
-      ].join('')
-
-      const triggerDisabled = fixtureEl.querySelector('button[disabled]')
-      const tab = new Tab(triggerDisabled)
-
-      triggerDisabled.addEventListener('shown.bs.tab', () => {
-        throw new Error('should not trigger shown event')
-      })
-
-      tab.show()
-      setTimeout(() => {
-        expect().nothing()
-        done()
-      }, 30)
-    })
-
-    it('should not fire shown when tab has disabled class', done => {
-      fixtureEl.innerHTML = [
-        '<ul class="nav nav-tabs" role="tablist">',
-        '  <li class="nav-item" role="presentation"><a href="#home" class="nav-link active" role="tab" aria-selected="true">Home</a></li>',
-        '  <li class="nav-item" role="presentation"><a href="#profile" class="nav-link disabled" role="tab">Profile</a></li>',
-        '</ul>',
-        '<div class="tab-content">',
-        '  <div class="tab-pane active" id="home" role="tabpanel"></div>',
-        '  <div class="tab-pane" id="profile" role="tabpanel"></div>',
-        '</div>'
-      ].join('')
-
-      const triggerDisabled = fixtureEl.querySelector('a.disabled')
-      const tab = new Tab(triggerDisabled)
-
-      triggerDisabled.addEventListener('shown.bs.tab', () => {
-        throw new Error('should not trigger shown event')
-      })
-
-      tab.show()
-      setTimeout(() => {
-        expect().nothing()
-        done()
-      }, 30)
-    })
-
     it('show and shown events should reference correct relatedTarget', done => {
       fixtureEl.innerHTML = [
         '<ul class="nav nav-tabs" role="tablist">',
@@ -695,5 +643,74 @@ describe('Tab', () => {
 
       secondNavEl.click()
     })
+
+    it('should prevent default when the trigger is <a> or <area>', done => {
+      fixtureEl.innerHTML = [
+        '<ul class="nav" role="tablist">',
+        '  <li><a type="button" href="#test"  class="active" role="tab" data-bs-toggle="tab">Home</a></li>',
+        '  <li><a type="button" href="#test2" role="tab" data-bs-toggle="tab">Home</a></li>',
+        '</ul>'
+      ].join('')
+
+      const tabEl = fixtureEl.querySelector('[href="#test2"]')
+      spyOn(Event.prototype, 'preventDefault').and.callThrough()
+
+      tabEl.addEventListener('shown.bs.tab', () => {
+        expect(tabEl.classList.contains('active')).toEqual(true)
+        expect(Event.prototype.preventDefault).toHaveBeenCalled()
+        done()
+      })
+
+      tabEl.click()
+    })
+
+    it('should not fire shown when tab has disabled attribute', done => {
+      fixtureEl.innerHTML = [
+        '<ul class="nav nav-tabs" role="tablist">',
+        '  <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
+        '  <li class="nav-item" role="presentation"><button type="button" data-bs-target="#profile" class="nav-link" disabled role="tab">Profile</button></li>',
+        '</ul>',
+        '<div class="tab-content">',
+        '  <div class="tab-pane active" id="home" role="tabpanel"></div>',
+        '  <div class="tab-pane" id="profile" role="tabpanel"></div>',
+        '</div>'
+      ].join('')
+
+      const triggerDisabled = fixtureEl.querySelector('button[disabled]')
+      triggerDisabled.addEventListener('shown.bs.tab', () => {
+        throw new Error('should not trigger shown event')
+      })
+
+      triggerDisabled.click()
+      setTimeout(() => {
+        expect().nothing()
+        done()
+      }, 30)
+    })
+
+    it('should not fire shown when tab has disabled class', done => {
+      fixtureEl.innerHTML = [
+        '<ul class="nav nav-tabs" role="tablist">',
+        '  <li class="nav-item" role="presentation"><a href="#home" class="nav-link active" role="tab" aria-selected="true">Home</a></li>',
+        '  <li class="nav-item" role="presentation"><a href="#profile" class="nav-link disabled" role="tab">Profile</a></li>',
+        '</ul>',
+        '<div class="tab-content">',
+        '  <div class="tab-pane active" id="home" role="tabpanel"></div>',
+        '  <div class="tab-pane" id="profile" role="tabpanel"></div>',
+        '</div>'
+      ].join('')
+
+      const triggerDisabled = fixtureEl.querySelector('a.disabled')
+
+      triggerDisabled.addEventListener('shown.bs.tab', () => {
+        throw new Error('should not trigger shown event')
+      })
+
+      triggerDisabled.click()
+      setTimeout(() => {
+        expect().nothing()
+        done()
+      }, 30)
+    })
   })
 })