mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-17 19:06:40 +02:00
Collapse supports multi-target thanks to @vanduynslagerp (#22713)
This commit is contained in:
@@ -32,6 +32,35 @@ You can use a link with the `href` attribute, or a button with the `data-target`
|
|||||||
</div>
|
</div>
|
||||||
{% endexample %}
|
{% endexample %}
|
||||||
|
|
||||||
|
## Multiple triggers / targets
|
||||||
|
|
||||||
|
A `<button>` or `<a>` can show and hide multiple elements by referencing them with a JQuery selector in its `href` or `data-target` attribute.
|
||||||
|
Multiple `<button>` or `<a>` can show and hide an element if they each reference it with their `href` or `data-target` attribute
|
||||||
|
|
||||||
|
{% example html %}
|
||||||
|
<p>
|
||||||
|
<a class="btn btn-primary" data-toggle="collapse" href="#multiCollapseExample1" aria-expanded="false" aria-controls="multiCollapseExample1">Toggle first element</a>
|
||||||
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#multiCollapseExample2" aria-expanded="false" aria-controls="multiCollapseExample1">Toggle second element</button>
|
||||||
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target=".multi-collapse" aria-expanded="false" aria-controls="multiCollapseExample1 multiCollapseExample2">Toggle both elements</button>
|
||||||
|
</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="collapse multi-collapse" id="multiCollapseExample1">
|
||||||
|
<div class="card card-block">
|
||||||
|
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="collapse multi-collapse" id="multiCollapseExample2">
|
||||||
|
<div class="card card-block">
|
||||||
|
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endexample %}
|
||||||
|
|
||||||
## Accordion example
|
## Accordion example
|
||||||
|
|
||||||
Using the [card]({{ site.baseurl }}/docs/{{ site.docs_version }}/components/card/) component, you can extend the default collapse behavior to create an accordion.
|
Using the [card]({{ site.baseurl }}/docs/{{ site.docs_version }}/components/card/) component, you can extend the default collapse behavior to create an accordion.
|
||||||
@@ -129,7 +158,7 @@ These classes can be found in `_transitions.scss`.
|
|||||||
|
|
||||||
### Via data attributes
|
### Via data attributes
|
||||||
|
|
||||||
Just add `data-toggle="collapse"` and a `data-target` to the element to automatically assign control of a collapsible element. The `data-target` attribute accepts a CSS selector to apply the collapse to. Be sure to add the class `collapse` to the collapsible element. If you'd like it to default open, add the additional class `show`.
|
Just add `data-toggle="collapse"` and a `data-target` to the element to automatically assign control of one or more collapsible elements. The `data-target` attribute accepts a CSS selector to apply the collapse to. Be sure to add the class `collapse` to the collapsible element. If you'd like it to default open, add the additional class `show`.
|
||||||
|
|
||||||
To add accordion-like group management to a collapsible area, add the data attribute `data-parent="#selector"`. Refer to the demo to see this in action.
|
To add accordion-like group management to a collapsible area, add the data attribute `data-parent="#selector"`. Refer to the demo to see this in action.
|
||||||
|
|
||||||
|
@@ -77,6 +77,14 @@ const Collapse = (($) => {
|
|||||||
`[data-toggle="collapse"][href="#${element.id}"],` +
|
`[data-toggle="collapse"][href="#${element.id}"],` +
|
||||||
`[data-toggle="collapse"][data-target="#${element.id}"]`
|
`[data-toggle="collapse"][data-target="#${element.id}"]`
|
||||||
))
|
))
|
||||||
|
const tabToggles = $(Selector.DATA_TOGGLE)
|
||||||
|
for (let i = 0; i < tabToggles.length; i++) {
|
||||||
|
const elem = tabToggles[i]
|
||||||
|
const selector = Util.getSelectorFromElement(elem)
|
||||||
|
if (selector !== null && $(selector).filter(element).length > 0) {
|
||||||
|
this._triggerArray.push(elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._parent = this._config.parent ? this._getParent() : null
|
this._parent = this._config.parent ? this._getParent() : null
|
||||||
|
|
||||||
@@ -215,9 +223,17 @@ const Collapse = (($) => {
|
|||||||
.removeClass(ClassName.SHOW)
|
.removeClass(ClassName.SHOW)
|
||||||
|
|
||||||
if (this._triggerArray.length) {
|
if (this._triggerArray.length) {
|
||||||
$(this._triggerArray)
|
for (let i = 0; i < this._triggerArray.length; i++) {
|
||||||
.addClass(ClassName.COLLAPSED)
|
const trigger = this._triggerArray[i]
|
||||||
.attr('aria-expanded', false)
|
const selector = Util.getSelectorFromElement(trigger)
|
||||||
|
if (selector !== null) {
|
||||||
|
const $elem = $(selector)
|
||||||
|
if (!$elem.hasClass(ClassName.SHOW)) {
|
||||||
|
$(trigger).addClass(ClassName.COLLAPSED)
|
||||||
|
.attr('aria-expanded', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setTransitioning(true)
|
this.setTransitioning(true)
|
||||||
@@ -349,11 +365,14 @@ const Collapse = (($) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = Collapse._getTargetFromElement(this)
|
const $trigger = $(this)
|
||||||
const data = $(target).data(DATA_KEY)
|
const selector = Util.getSelectorFromElement(this)
|
||||||
const config = data ? 'toggle' : $(this).data()
|
$(selector).each(function () {
|
||||||
|
const $target = $(this)
|
||||||
Collapse._jQueryInterface.call($(target), config)
|
const data = $target.data(DATA_KEY)
|
||||||
|
const config = data ? 'toggle' : $trigger.data()
|
||||||
|
Collapse._jQueryInterface.call($target, config)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@@ -52,8 +52,28 @@ $(function () {
|
|||||||
assert.ok(!/height/i.test($el.attr('style')), 'has height reset')
|
assert.ok(!/height/i.test($el.attr('style')), 'has height reset')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
QUnit.test('should show multiple collapsed elements', function (assert) {
|
||||||
|
assert.expect(4)
|
||||||
|
var done = assert.async()
|
||||||
|
var $target = $('<a role="button" data-toggle="collapse" class="collapsed" href=".multi"/>').appendTo('#qunit-fixture')
|
||||||
|
var $el = $('<div class="collapse multi"/>').appendTo('#qunit-fixture')
|
||||||
|
var $el2 = $('<div class="collapse multi"/>').appendTo('#qunit-fixture')
|
||||||
|
$el.one('shown.bs.collapse', function () {
|
||||||
|
assert.ok($el.hasClass('show'), 'has class "show"')
|
||||||
|
assert.ok(!/height/i.test($el.attr('style')), 'has height reset')
|
||||||
|
})
|
||||||
|
$el2.one('shown.bs.collapse', function () {
|
||||||
|
assert.ok($el2.hasClass('show'), 'has class "show"')
|
||||||
|
assert.ok(!/height/i.test($el2.attr('style')), 'has height reset')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
$target.trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
QUnit.test('should collapse only the first collapse', function (assert) {
|
QUnit.test('should collapse only the first collapse', function (assert) {
|
||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
|
var done = assert.async()
|
||||||
var html = [
|
var html = [
|
||||||
'<div class="panel-group" id="accordion1">',
|
'<div class="panel-group" id="accordion1">',
|
||||||
'<div class="panel">',
|
'<div class="panel">',
|
||||||
@@ -69,10 +89,11 @@ $(function () {
|
|||||||
$(html).appendTo('#qunit-fixture')
|
$(html).appendTo('#qunit-fixture')
|
||||||
var $el1 = $('#collapse1')
|
var $el1 = $('#collapse1')
|
||||||
var $el2 = $('#collapse2')
|
var $el2 = $('#collapse2')
|
||||||
$el1.bootstrapCollapse('show')
|
$el1.one('shown.bs.collapse', function () {
|
||||||
|
assert.ok($el1.hasClass('show'))
|
||||||
assert.ok($el1.hasClass('show'))
|
assert.ok($el2.hasClass('show'))
|
||||||
assert.ok($el2.hasClass('show'))
|
done()
|
||||||
|
}).bootstrapCollapse('show')
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('should hide a collapsed element', function (assert) {
|
QUnit.test('should hide a collapsed element', function (assert) {
|
||||||
@@ -588,4 +609,68 @@ $(function () {
|
|||||||
|
|
||||||
$target.trigger($.Event('click'))
|
$target.trigger($.Event('click'))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
QUnit.test('should add "collapsed" class to triggers only when all the targeted collapse are hidden', function (assert) {
|
||||||
|
assert.expect(9)
|
||||||
|
var done = assert.async()
|
||||||
|
|
||||||
|
var $trigger1 = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture')
|
||||||
|
var $trigger2 = $('<a role="button" data-toggle="collapse" href="#test2"/>').appendTo('#qunit-fixture')
|
||||||
|
var $trigger3 = $('<a role="button" data-toggle="collapse" href=".multi"/>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
|
var $target1 = $('<div id="test1" class="multi"/>').appendTo('#qunit-fixture')
|
||||||
|
var $target2 = $('<div id="test2" class="multi"/>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
|
$target2.one('shown.bs.collapse', function () {
|
||||||
|
assert.ok(!$trigger1.hasClass('collapsed'), 'trigger1 does not have collapsed class')
|
||||||
|
assert.ok(!$trigger2.hasClass('collapsed'), 'trigger2 does not have collapsed class')
|
||||||
|
assert.ok(!$trigger3.hasClass('collapsed'), 'trigger3 does not have collapsed class')
|
||||||
|
$target2.one('hidden.bs.collapse', function () {
|
||||||
|
assert.ok(!$trigger1.hasClass('collapsed'), 'trigger1 does not have collapsed class')
|
||||||
|
assert.ok($trigger2.hasClass('collapsed'), 'trigger2 has collapsed class')
|
||||||
|
assert.ok(!$trigger3.hasClass('collapsed'), 'trigger3 does not have collapsed class')
|
||||||
|
$target1.one('hidden.bs.collapse', function () {
|
||||||
|
assert.ok($trigger1.hasClass('collapsed'), 'trigger1 has collapsed class')
|
||||||
|
assert.ok($trigger2.hasClass('collapsed'), 'trigger2 has collapsed class')
|
||||||
|
assert.ok($trigger3.hasClass('collapsed'), 'trigger3 has collapsed class')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
$trigger1.trigger('click')
|
||||||
|
})
|
||||||
|
$trigger2.trigger('click')
|
||||||
|
})
|
||||||
|
$trigger3.trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
|
QUnit.test('should set aria-expanded="true" to triggers targetting shown collaspe and aria-expanded="false" only when all the targeted collapses are shown', function (assert) {
|
||||||
|
assert.expect(9)
|
||||||
|
var done = assert.async()
|
||||||
|
|
||||||
|
var $trigger1 = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture')
|
||||||
|
var $trigger2 = $('<a role="button" data-toggle="collapse" href="#test2"/>').appendTo('#qunit-fixture')
|
||||||
|
var $trigger3 = $('<a role="button" data-toggle="collapse" href=".multi"/>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
|
var $target1 = $('<div id="test1" class="multi collapse"/>').appendTo('#qunit-fixture')
|
||||||
|
var $target2 = $('<div id="test2" class="multi collapse"/>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
|
$target2.one('shown.bs.collapse', function () {
|
||||||
|
assert.strictEqual($trigger1.attr('aria-expanded'), 'true', 'aria-expanded on trigger1 is "true"')
|
||||||
|
assert.strictEqual($trigger2.attr('aria-expanded'), 'true', 'aria-expanded on trigger2 is "true"')
|
||||||
|
assert.strictEqual($trigger3.attr('aria-expanded'), 'true', 'aria-expanded on trigger3 is "true"')
|
||||||
|
$target2.one('hidden.bs.collapse', function () {
|
||||||
|
assert.strictEqual($trigger1.attr('aria-expanded'), 'true', 'aria-expanded on trigger1 is "true"')
|
||||||
|
assert.strictEqual($trigger2.attr('aria-expanded'), 'false', 'aria-expanded on trigger2 is "false"')
|
||||||
|
assert.strictEqual($trigger3.attr('aria-expanded'), 'true', 'aria-expanded on trigger3 is "true"')
|
||||||
|
$target1.one('hidden.bs.collapse', function () {
|
||||||
|
assert.strictEqual($trigger1.attr('aria-expanded'), 'false', 'aria-expanded on trigger1 is "fasle"')
|
||||||
|
assert.strictEqual($trigger2.attr('aria-expanded'), 'false', 'aria-expanded on trigger2 is "false"')
|
||||||
|
assert.strictEqual($trigger3.attr('aria-expanded'), 'false', 'aria-expanded on trigger3 is "false"')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
$trigger1.trigger('click')
|
||||||
|
})
|
||||||
|
$trigger2.trigger('click')
|
||||||
|
})
|
||||||
|
$trigger3.trigger('click')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user