0
0
mirror of https://github.com/twbs/bootstrap.git synced 2025-01-17 09:52:29 +01:00

buttons plugin : avoid multiple change event trigger (#31000)

- 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>
This commit is contained in:
Laussel Loïc 2020-10-02 16:40:20 +02:00 committed by GitHub
parent d9b4426b07
commit 24572b1577
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 6 deletions

View 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",

View 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')
}
}
})

View 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">' +