Skip to content

Commit 36e3d07

Browse files
committed
Merge pull request twbs#14686 from twbs/collapsed-class-manual-invocation
Handle `collapsed` class on triggers even when manually invoked
2 parents a7f58a8 + ed3a65f commit 36e3d07

File tree

2 files changed

+99
-38
lines changed

2 files changed

+99
-38
lines changed

js/collapse.js

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@
1616
var Collapse = function (element, options) {
1717
this.$element = $(element)
1818
this.options = $.extend({}, Collapse.DEFAULTS, options)
19+
this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
1920
this.transitioning = null
2021

21-
if (this.options.parent) this.$parent = $(this.options.parent)
22+
if (this.options.parent) {
23+
this.$parent = this.getParent()
24+
} else {
25+
this.addAriaAndCollapsedClass(this.$element, this.$trigger)
26+
}
27+
2228
if (this.options.toggle) this.toggle()
2329
}
2430

@@ -27,7 +33,8 @@
2733
Collapse.TRANSITION_DURATION = 350
2834

2935
Collapse.DEFAULTS = {
30-
toggle: true
36+
toggle: true,
37+
trigger: '[data-toggle="collapse"]'
3138
}
3239

3340
Collapse.prototype.dimension = function () {
@@ -62,6 +69,10 @@
6269
.addClass('collapsing')[dimension](0)
6370
.attr('aria-expanded', true)
6471

72+
this.$trigger
73+
.removeClass('collapsed')
74+
.attr('aria-expanded', true)
75+
6576
this.transitioning = 1
6677

6778
var complete = function () {
@@ -98,6 +109,10 @@
98109
.removeClass('collapse in')
99110
.attr('aria-expanded', false)
100111

112+
this.$trigger
113+
.addClass('collapsed')
114+
.attr('aria-expanded', false)
115+
101116
this.transitioning = 1
102117

103118
var complete = function () {
@@ -120,6 +135,33 @@
120135
this[this.$element.hasClass('in') ? 'hide' : 'show']()
121136
}
122137

138+
Collapse.prototype.getParent = function () {
139+
return $(this.options.parent)
140+
.find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
141+
.each($.proxy(function (i, element) {
142+
var $element = $(element)
143+
this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
144+
}, this))
145+
.end()
146+
}
147+
148+
Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
149+
var isOpen = $element.hasClass('in')
150+
151+
$element.attr('aria-expanded', isOpen)
152+
$trigger
153+
.toggleClass('collapsed', !isOpen)
154+
.attr('aria-expanded', isOpen)
155+
}
156+
157+
function getTargetFromTrigger($trigger) {
158+
var href
159+
var target = $trigger.attr('data-target')
160+
|| (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
161+
162+
return $(target)
163+
}
164+
123165

124166
// COLLAPSE PLUGIN DEFINITION
125167
// ==========================
@@ -155,22 +197,13 @@
155197
// =================
156198

157199
$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
158-
var href
159200
var $this = $(this)
160-
var target = $this.attr('data-target')
161-
|| e.preventDefault()
162-
|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
163-
var $target = $(target)
201+
202+
if (!$this.attr('data-target')) e.preventDefault()
203+
204+
var $target = getTargetFromTrigger($this)
164205
var data = $target.data('bs.collapse')
165-
var option = data ? 'toggle' : $this.data()
166-
var parent = $this.attr('data-parent')
167-
var $parent = parent && $(parent)
168-
169-
if (!data || !data.transitioning) {
170-
if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed').attr('aria-expanded', false)
171-
var isCollapsed = $target.hasClass('in')
172-
$this.toggleClass('collapsed', isCollapsed).attr('aria-expanded', !isCollapsed)
173-
}
206+
var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
174207

175208
Plugin.call($target, option)
176209
})

js/tests/unit/collapse.js

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ $(function () {
7979

8080
$('<div id="test1"/>')
8181
.appendTo('#qunit-fixture')
82-
.on('show.bs.collapse', function () {
82+
.on('shown.bs.collapse', function () {
8383
ok(!$target.hasClass('collapsed'))
8484
start()
8585
})
@@ -94,7 +94,7 @@ $(function () {
9494

9595
$('<div id="test1" class="in"/>')
9696
.appendTo('#qunit-fixture')
97-
.on('hide.bs.collapse', function () {
97+
.on('hidden.bs.collapse', function () {
9898
ok($target.hasClass('collapsed'))
9999
start()
100100
})
@@ -137,12 +137,12 @@ $(function () {
137137
test('should remove "collapsed" class from active accordion target', function () {
138138
stop()
139139

140-
var accordionHTML = '<div id="accordion">'
141-
+ '<div class="accordion-group"/>'
142-
+ '<div class="accordion-group"/>'
143-
+ '<div class="accordion-group"/>'
140+
var accordionHTML = '<div class="panel-group" id="accordion">'
141+
+ '<div class="panel"/>'
142+
+ '<div class="panel"/>'
143+
+ '<div class="panel"/>'
144144
+ '</div>'
145-
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.accordion-group')
145+
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.panel')
146146

147147
var $target1 = $('<a data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0))
148148

@@ -156,7 +156,7 @@ $(function () {
156156

157157
$('<div id="body3"/>')
158158
.appendTo($groups.eq(2))
159-
.on('show.bs.collapse', function () {
159+
.on('shown.bs.collapse', function () {
160160
ok($target1.hasClass('collapsed'), 'inactive target 1 does have class "collapsed"')
161161
ok($target2.hasClass('collapsed'), 'inactive target 2 does have class "collapsed"')
162162
ok(!$target3.hasClass('collapsed'), 'active target 3 does not have class "collapsed"')
@@ -170,12 +170,12 @@ $(function () {
170170
test('should allow dots in data-parent', function () {
171171
stop()
172172

173-
var accordionHTML = '<div class="accordion">'
174-
+ '<div class="accordion-group"/>'
175-
+ '<div class="accordion-group"/>'
176-
+ '<div class="accordion-group"/>'
173+
var accordionHTML = '<div class="panel-group accordion">'
174+
+ '<div class="panel"/>'
175+
+ '<div class="panel"/>'
176+
+ '<div class="panel"/>'
177177
+ '</div>'
178-
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.accordion-group')
178+
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.panel')
179179

180180
var $target1 = $('<a data-toggle="collapse" href="#body1" data-parent=".accordion"/>').appendTo($groups.eq(0))
181181

@@ -189,7 +189,7 @@ $(function () {
189189

190190
$('<div id="body3"/>')
191191
.appendTo($groups.eq(2))
192-
.on('show.bs.collapse', function () {
192+
.on('shown.bs.collapse', function () {
193193
ok($target1.hasClass('collapsed'), 'inactive target 1 does have class "collapsed"')
194194
ok($target2.hasClass('collapsed'), 'inactive target 2 does have class "collapsed"')
195195
ok(!$target3.hasClass('collapsed'), 'active target 3 does not have class "collapsed"')
@@ -207,7 +207,7 @@ $(function () {
207207

208208
$('<div id="test1"/>')
209209
.appendTo('#qunit-fixture')
210-
.on('show.bs.collapse', function () {
210+
.on('shown.bs.collapse', function () {
211211
equal($target.attr('aria-expanded'), 'true', 'aria-expanded on target is "true"')
212212
start()
213213
})
@@ -222,7 +222,7 @@ $(function () {
222222

223223
$('<div id="test1" class="in"/>')
224224
.appendTo('#qunit-fixture')
225-
.on('hide.bs.collapse', function () {
225+
.on('hidden.bs.collapse', function () {
226226
equal($target.attr('aria-expanded'), 'false', 'aria-expanded on target is "false"')
227227
start()
228228
})
@@ -233,12 +233,12 @@ $(function () {
233233
test('should change aria-expanded from active accordion target to "false" and set the newly active one to "true"', function () {
234234
stop()
235235

236-
var accordionHTML = '<div id="accordion">'
237-
+ '<div class="accordion-group"/>'
238-
+ '<div class="accordion-group"/>'
239-
+ '<div class="accordion-group"/>'
236+
var accordionHTML = '<div class="panel-group" id="accordion">'
237+
+ '<div class="panel"/>'
238+
+ '<div class="panel"/>'
239+
+ '<div class="panel"/>'
240240
+ '</div>'
241-
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.accordion-group')
241+
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.panel')
242242

243243
var $target1 = $('<a data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0))
244244

@@ -252,7 +252,7 @@ $(function () {
252252

253253
$('<div id="body3" aria-expanded="false"/>')
254254
.appendTo($groups.eq(2))
255-
.on('show.bs.collapse', function () {
255+
.on('shown.bs.collapse', function () {
256256
equal($target1.attr('aria-expanded'), 'false', 'inactive target 1 has aria-expanded="false"')
257257
equal($target2.attr('aria-expanded'), 'false', 'inactive target 2 has aria-expanded="false"')
258258
equal($target3.attr('aria-expanded'), 'true', 'active target 3 has aria-expanded="false"')
@@ -298,4 +298,32 @@ $(function () {
298298
}, 1)
299299
})
300300

301+
test('should add "collapsed" class to target when collapse is hidden via manual invocation', function () {
302+
stop()
303+
304+
var $target = $('<a data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture')
305+
306+
$('<div id="test1" class="in"/>')
307+
.appendTo('#qunit-fixture')
308+
.on('hidden.bs.collapse', function () {
309+
ok($target.hasClass('collapsed'))
310+
start()
311+
})
312+
.bootstrapCollapse('hide')
313+
})
314+
315+
test('should remove "collapsed" class from target when collapse is shown via manual invocation', function () {
316+
stop()
317+
318+
var $target = $('<a data-toggle="collapse" class="collapsed" href="#test1"/>').appendTo('#qunit-fixture')
319+
320+
$('<div id="test1"/>')
321+
.appendTo('#qunit-fixture')
322+
.on('shown.bs.collapse', function () {
323+
ok(!$target.hasClass('collapsed'))
324+
start()
325+
})
326+
.bootstrapCollapse('show')
327+
})
328+
301329
})

0 commit comments

Comments
 (0)