]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
buttons plugin : avoid multiple change event trigger (#31000)
authorLaussel Loïc <loic.laussel@orange.com>
Fri, 2 Oct 2020 14:40:20 +0000 (16:40 +0200)
committerGitHub <noreply@github.com>
Fri, 2 Oct 2020 14:40:20 +0000 (17:40 +0300)
- add unit test to count how many events are thrown when widget contains multiple tags inside label
- add a parameter to toggle, if click event is provided onto an input then don't trigger another change event already thrown by the browser
- simplify the case where toggle interface is called click provide from input itself OR it's a button without label. If label is present, then browser propagate click event from childrens through label and then cause multiple calls to toggle
- the test assumes that `.btn` class is always set onto the label if there's one, otherwise need to update this plugin and look for label around the input

Test with keyboard, mouse and js click call

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
.bundlewatch.config.json
js/src/button.js
js/tests/unit/button.js

index e12dda91810ad901d5f2fc495f36d242988eaa85..fb76d8dd83b870250c944eab71d661e09cf15f84 100644 (file)
@@ -26,7 +26,7 @@
     },
     {
       "path": "./dist/js/bootstrap.bundle.js",
-      "maxSize": "47.50 kB"
+      "maxSize": "47.5 kB"
     },
     {
       "path": "./dist/js/bootstrap.bundle.min.js",
@@ -34,7 +34,7 @@
     },
     {
       "path": "./dist/js/bootstrap.js",
-      "maxSize": "25 kB"
+      "maxSize": "25.5 kB"
     },
     {
       "path": "./dist/js/bootstrap.min.js",
index d793785829fc452e1d60e91f81334ccc194a43b5..c95013a98cd3d866a0c0af5c7564fc3732a1aad1 100644 (file)
@@ -46,6 +46,7 @@ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
 class Button {
   constructor(element) {
     this._element = element
+    this.shouldAvoidTriggerChange = false
   }
 
   // Getters
@@ -83,7 +84,9 @@ class Button {
             input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE)
           }
 
-          $(input).trigger('change')
+          if (!this.shouldAvoidTriggerChange) {
+            $(input).trigger('change')
+          }
         }
 
         input.focus()
@@ -109,7 +112,7 @@ class Button {
 
   // Static
 
-  static _jQueryInterface(config) {
+  static _jQueryInterface(config, avoidTriggerChange) {
     return this.each(function () {
       const $element = $(this)
       let data = $element.data(DATA_KEY)
@@ -119,6 +122,8 @@ class Button {
         $element.data(DATA_KEY, data)
       }
 
+      data.shouldAvoidTriggerChange = avoidTriggerChange
+
       if (config === 'toggle') {
         data[config]()
       }
@@ -151,8 +156,8 @@ $(document)
         return
       }
 
-      if (initialButton.tagName !== 'LABEL' || inputBtn && inputBtn.type !== 'checkbox') {
-        Button._jQueryInterface.call($(button), 'toggle')
+      if (initialButton.tagName === 'INPUT' || button.tagName !== 'LABEL') {
+        Button._jQueryInterface.call($(button), 'toggle', initialButton.tagName === 'INPUT')
       }
     }
   })
index 2adffedd9fe656b6bb698a1560cfb14d929cd94c..1bd62b6b8b60787590436f33ecdd11eec514d4cb 100644 (file)
@@ -180,6 +180,32 @@ $(function () {
     $group.find('label').trigger('click')
   })
 
+  QUnit.test('should trigger label change event only once', function (assert) {
+    assert.expect(1)
+    var done = assert.async()
+    var countChangeEvent = 0
+
+    var groupHTML = '<div class="btn-group" data-toggle="buttons">' +
+      '<label class="btn btn-primary">' +
+      '<input type="checkbox"><span class="check">✓</span> <i class="far fa-clipboard"></i> <span class="d-none d-lg-inline">checkbox</span>' +
+      '</label>' +
+      '</div>'
+    var $group = $(groupHTML).appendTo('#qunit-fixture')
+
+    var $btn = $group.children().eq(0)
+
+    $group.find('label').on('change', function () {
+      countChangeEvent++
+    })
+
+    setTimeout(function () {
+      assert.ok(countChangeEvent === 1, 'onchange event fired only once')
+      done()
+    }, 5)
+
+    $btn[0].click()
+  })
+
   QUnit.test('should check for closest matching toggle', function (assert) {
     assert.expect(18)
     var groupHTML = '<div class="btn-group" data-toggle="buttons">' +