Angular 1.4.8 Carousel Directives

Solution for SO question: http://stackoverflow.com/questions/35113678/fading-content-in-a-carousel-with-angular/35117897

by Roger Sanchez

HTML

<div ng-controller="MyController as vm">
  <carousel panels="vm.panels">
    <carousel-panel>
      <h1>{{$title}}</h1>
      <p>{{$body}}</p>
    </carousel-panel>
    <button carousel-prev>
      &lsaquo; Prev
    </button>
    <button carousel-next>
      Next &rsaquo;
    </button>
  </carousel>
</div>

CSS

carousel-panel > ng-transclude > * {
  -webkit-transition: opacity 0.5s ease-in-out;
  -moz-transition: opacity 0.5s ease-in-out;
  -ms-transition: opacity 0.5s ease-in-out;
  -o-transition: opacity 0.5s ease-in-out;
  opacity: 1;
}

carousel-panel.fade > ng-transclude > * {
  opacity: 0;
}

JavaScript

angular.module('myApp.carousel', [])
  .controller('CarouselController', CarouselController)
  .directive('carousel', carouselDirective)
  .directive('carouselPanel', carouselPanelDirective)
  .directive('carouselNext', carouselNextDirective)
  .directive('carouselPrev', carouselPrevDirective)
;

function CarouselController() {
  var carousel = this;
  carousel.slide = 0;
  carousel.current = function() {
    if (carousel.panels && carousel.panels.length) {
      return carousel.panels[carousel.slide];
    }
  };
  carousel.next = function() {
    if (carousel.panels && carousel.panels.length) {
      if (carousel.slide >= carousel.panels.length - 1) {
        carousel.slide = 0;
      } else {
        carousel.slide++;
      }
    }
  };
  carousel.prev = function() {
    if (carousel.panels && carousel.panels.length) {
      if (carousel.slide <= 0) {
        carousel.slide = carousel.panels.length - 1;
      } else {
        carousel.slide--;
      }
    }
  };
}

function carouselDirective() {
  return {
    bindToController: {
      panels: '='
    },
    controller: 'CarouselController',
    controllerAs: 'carousel',
    scope: true,
    template: '<ng-transclude></ng-transclude>',
    transclude: true
  };
}

function carouselPanelDirective($timeout) {
  return {
    link: postLink,
    require: '^carousel',
    template: '<ng-transclude></ng-transclude>',
    transclude: true
  };

  function postLink(scope, iElement, iAttrs, carousel) {
    scope.$watch(currentSlide, transition);
    
    function currentSlide() {
      return carousel.slide;
    }
    
    function fadeOut() {
      iElement.addClass('fade');
    }
    
    function fadeIn() {
      iElement.removeClass('fade');      
    }
    
    function refresh() {
      var current = carousel.current();
      scope.$title = current.title;
      scope.$body = current.body;
    }
    
    function transition(currentSlide, previousSlide) {
      if (currentSlide === previousSlide) {
       ...