UNPKG

angular-ui-bootstrap

Version:

Native AngularJS (Angular) directives for Bootstrap

146 lines (131 loc) 5.08 kB
angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse', 'ui.bootstrap.tabindex']) .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 || 'uib/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 restrict: 'A', templateUrl: function(element, attrs) { return attrs.templateUrl || 'uib/template/accordion/accordion-group.html'; }, scope: { heading: '@', // Interpolate the heading attribute onto this scope panelClass: '@?', // Ditto with panelClass isOpen: '=?', isDisabled: '=?' }, controller: function() { this.setHeading = function(element) { this.heading = element; }; }, link: function(scope, element, attrs, accordionCtrl) { element.addClass('panel'); accordionCtrl.addGroup(scope); scope.openClass = attrs.openClass || 'panel-open'; scope.panelClass = attrs.panelClass || 'panel-default'; 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; } } }; var id = 'accordiongroup-' + scope.$id + '-' + Math.floor(Math.random() * 10000); scope.headingId = id + '-tab'; scope.panelId = id + '-panel'; } }; }) // 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', link: function(scope, element, attrs, controller) { scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) { if (heading) { var elem = angular.element(element[0].querySelector(getHeaderSelectors())); elem.html(''); elem.append(heading); } }); } }; function getHeaderSelectors() { return 'uib-accordion-header,' + 'data-uib-accordion-header,' + 'x-uib-accordion-header,' + 'uib\\:accordion-header,' + '[uib-accordion-header],' + '[data-uib-accordion-header],' + '[x-uib-accordion-header]'; } });