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