text: angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
  
  .constant('uibAccordionConfig', {
    closeOthers: true
  })
  
  .controller('UibAccordionController', ['$scope', '$attrs', 'uibAccordionConfig', function($scope, $attrs, accordionConfig) {
    // This array keeps track of the accordion groups
    this.groups = [];
  
    // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
    this.closeOthers = function(openGroup) {
      var closeOthers = angular.isDefined($attrs.closeOthers) ?
        $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
      if (closeOthers) {
        angular.forEach(this.groups, function(group) {
          if (group !== openGroup) {
            group.isOpen = false;
          }
        });
      }
    };
  
    // This is called from the accordion-group directive to add itself to the accordion
    this.addGroup = function(groupScope) {
      var that = this;
      this.groups.push(groupScope);
  
      groupScope.$on('$destroy', function(event) {
        that.removeGroup(groupScope);
      });
    };
  
    // This is called from the accordion-group directive when to remove itself
    this.removeGroup = function(group) {
      var index = this.groups.indexOf(group);
      if (index !== -1) {
        this.groups.splice(index, 1);
      }
    };
  
  }])
  
  // The accordion directive simply sets up the directive controller
  // and adds an accordion CSS class to itself element.
  .directive('uibAccordion', function() {
    return {
      controller: 'UibAccordionController',
      controllerAs: 'accordion',
      transclude: true,
      templateUrl: function(element, attrs) {
        return attrs.templateUrl || 'template/accordion/accordion.html';
      }
    };
  })
  
  // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
  .directive('uibAccordionGroup', function() {
    return {
      require: '^uibAccordion',         // We need this directive to be inside an accordion
      transclude: true,              // It transcludes the contents of the directive into the template
      replace: true,                // The element containing the directive will be replaced with the template
      templateUrl: function(element, attrs) {
        return attrs.templateUrl || 'template/accordion/accordion-group.html';
      },
      scope: {
        heading: '@',               // Interpolate the heading attribute onto this scope
        isOpen: '=?',
        isDisabled: '=?'
      },
      controller: function() {
        this.setHeading = function(element) {
          this.heading = element;
        };
      },
      link: function(scope, element, attrs, accordionCtrl) {
        accordionCtrl.addGroup(scope);
  
        scope.openClass = attrs.openClass || 'panel-open';
        scope.panelClass = attrs.panelClass;
        scope.$watch('isOpen', function(value) {
          element.toggleClass(scope.openClass, !!value);
          if (value) {
            accordionCtrl.closeOthers(scope);
          }
        });
  
        scope.toggleOpen = function($event) {
          if (!scope.isDisabled) {
            if (!$event || $event.which === 32) {
              scope.isOpen = !scope.isOpen;
            }
          }
        };
      }
    };
  })
  
  // Use accordion-heading below an accordion-group to provide a heading containing HTML
  .directive('uibAccordionHeading', function() {
    return {
      transclude: true,   // Grab the contents to be used as the heading
      template: '',       // In effect remove this element!
      replace: true,
      require: '^uibAccordionGroup',
      link: function(scope, element, attrs, accordionGroupCtrl, transclude) {
        // Pass the heading to the accordion-group controller
        // so that it can be transcluded into the right place in the template
        // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
        accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
      }
    };
  })
  
  // Use in the accordion-group template to indicate where you want the heading to be transcluded
  // You must provide the property on the accordion-group controller that will hold the transcluded element
  .directive('uibAccordionTransclude', function() {
    return {
      require: ['?^uibAccordionGroup', '?^accordionGroup'],
      link: function(scope, element, attrs, controller) {
        controller = controller[0] ? controller[0] : controller[1]; // Delete after we remove deprecation
        scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {
          if (heading) {
            element.find('span').html('');
            element.find('span').append(heading);
          }
        });
      }
    };
  });
  
  /* Deprecated accordion below */
  
  angular.module('ui.bootstrap.accordion')
  
    .value('$accordionSuppressWarning', false)
  
    .controller('AccordionController', ['$scope', '$attrs', '$controller', '$log', '$accordionSuppressWarning', function($scope, $attrs, $controller, $log, $accordionSuppressWarning) {
      if (!$accordionSuppressWarning) {
        $log.warn('AccordionController is now deprecated. Use UibAccordionController instead.');
      }
  
      angular.extend(this, $controller('UibAccordionController', {
        $scope: $scope,
        $attrs: $attrs
      }));
    }])
  
    .directive('accordion', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
      return {
        restrict: 'EA',
        controller: 'AccordionController',
        controllerAs: 'accordion',
        transclude: true,
        replace: false,
        templateUrl: function(element, attrs) {
          return attrs.templateUrl || 'template/accordion/accordion.html';
        },
        link: function() {
          if (!$accordionSuppressWarning) {
            $log.warn('accordion is now deprecated. Use uib-accordion instead.');
          }
        }
      };
    }])
  
    .directive('accordionGroup', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
      return {
        require: '^accordion',         // We need this directive to be inside an accordion
        restrict: 'EA',
        transclude: true,              // It transcludes the contents of the directive into the template
        replace: true,                // The element containing the directive will be replaced with the template
        templateUrl: function(element, attrs) {
          return attrs.templateUrl || 'template/accordion/accordion-group.html';
        },
        scope: {
          heading: '@',               // Interpolate the heading attribute onto this scope
          isOpen: '=?',
          isDisabled: '=?'
        },
        controller: function() {
          this.setHeading = function(element) {
            this.heading = element;
          };
        },
        link: function(scope, element, attrs, accordionCtrl) {
          if (!$accordionSuppressWarning) {
            $log.warn('accordion-group is now deprecated. Use uib-accordion-group instead.');
          }
  
          accordionCtrl.addGroup(scope);
  
          scope.openClass = attrs.openClass || 'panel-open';
          scope.panelClass = attrs.panelClass;
          scope.$watch('isOpen', function(value) {
            element.toggleClass(scope.openClass, !!value);
            if (value) {
              accordionCtrl.closeOthers(scope);
            }
          });
  
          scope.toggleOpen = function($event) {
            if (!scope.isDisabled) {
              if (!$event || $event.which === 32) {
                scope.isOpen = !scope.isOpen;
              }
            }
          };
        }
      };
    }])
  
    .directive('accordionHeading', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
      return {
        restrict: 'EA',
        transclude: true,   // Grab the contents to be used as the heading
        template: '',       // In effect remove this element!
        replace: true,
        require: '^accordionGroup',
        link: function(scope, element, attr, accordionGroupCtrl, transclude) {
          if (!$accordionSuppressWarning) {
            $log.warn('accordion-heading is now deprecated. Use uib-accordion-heading instead.');
          }
          // Pass the heading to the accordion-group controller
          // so that it can be transcluded into the right place in the template
          // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
          accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
        }
      };
    }])
  
    .directive('accordionTransclude', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
      return {
        require: '^accordionGroup',
        link: function(scope, element, attr, controller) {
          if (!$accordionSuppressWarning) {
            $log.warn('accordion-transclude is now deprecated. Use uib-accordion-transclude instead.');
          }
  
          scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
            if (heading) {
              element.find('span').html('');
              element.find('span').append(heading);
            }
          });
        }
      };
    }]);
  
  