I think the issue you're experiencing is that `$('.accordion-toggle:visible').length` is being retrieved **before** the panel has opened/closed.
You should use **shown.bs.collapse** and **hidden.bs.collapse** to detect when a panel has finished opening or closing.
Here's my crack. It's not quite there, but it's a fair bit cleaner (maybe).
var active = false,
$collapseBtn = $('#collapse_init'),
$accordion = $('#accordion');
$collapseBtn.on('click',function(){
active = ! active;
$('.panel-collapse').collapse( active ? 'show' : 'hide');
$('.panel-title').attr('data-toggle', active ? '' : 'collapse' );
})
$accordion.on({
'shown.bs.collapse': function () {
active = true;
$collapseBtn.text( 'Hide all' );
},
'hidden.bs.collapse': function ( e) {
var $this = $( this );
active = ! ! $('.panel-collapse:visible').not( $this ).length;
$collapseBtn.text( ( active ? 'Hide' : 'Show' ) + ' all' );
}
});
https://codepen.io/anon/pen/dRePNQ